<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <title>Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="https://goofyer.gitee.io/notes-on-computer-expertise/page/2/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
  
    <link rel="alternate" href="/notes-on-computer-expertise/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="shortcut icon" href="/notes-on-computer-expertise/favicon.png">
  
  
    
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/typeface-source-code-pro@0.0.71/index.min.css">

  
  
<link rel="stylesheet" href="/notes-on-computer-expertise/css/style.css">

  
    
<link rel="stylesheet" href="/notes-on-computer-expertise/fancybox/jquery.fancybox.min.css">

  
<meta name="generator" content="Hexo 5.4.0"></head>

<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/notes-on-computer-expertise/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/notes-on-computer-expertise/">Home</a>
        
          <a class="main-nav-link" href="/notes-on-computer-expertise/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/notes-on-computer-expertise/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="https://goofyer.gitee.io/notes-on-computer-expertise"></form>
      </div>
    </div>
  </div>
</header>

      <div class="outer">
        <section id="main">
  
    <article id="post-代码实战/unity 战棋" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/03/25/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/unity%20%E6%88%98%E6%A3%8B/" class="article-date">
  <time class="dt-published" datetime="2022-03-25T12:12:12.955Z" itemprop="datePublished">2022-03-25</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        
      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/03/25/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/unity%20%E6%88%98%E6%A3%8B/" data-id="cl403sxrm002gf8vu2b1xglk1" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-代码实战/unity反编译" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/03/23/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/unity%E5%8F%8D%E7%BC%96%E8%AF%91/" class="article-date">
  <time class="dt-published" datetime="2022-03-23T10:45:22.733Z" itemprop="datePublished">2022-03-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <p>第一步找到这个文件 assets\bin\Data\Managed\Assembly-CSharp.dll</p>
<p>反编译unity3d中Dll代码</p>
<p>第二步 用dotpeek打开dll文件</p>
<p><a target="_blank" rel="noopener" href="https://www.jetbrains.com/decompiler/download/download-thanks.html?platform=windows64">https://www.jetbrains.com/decompiler/download/download-thanks.html?platform=windows64</a></p>
<p>蓝图1</p>
<p>单个炉子</p>
<p>炉子和一圈轨道</p>
<p>  public void Import(BinaryReader r)<br>  {<br>    this.version = r.ReadInt32();<br>    this.cursorOffset_x = r.ReadInt32();<br>    this.cursorOffset_y = r.ReadInt32();<br>    this.cursorTargetArea = r.ReadInt32();<br>    this.dragBoxSize_x = r.ReadInt32();<br>    this.dragBoxSize_y = r.ReadInt32();<br>    this.primaryAreaIdx = r.ReadInt32();<br>    int length1 = (int) r.ReadByte();<br>    this.areas = length1 &gt;= 0 &amp;&amp; length1 &lt;= 64 &amp;&amp; this.primaryAreaIdx &gt;= -1 &amp;&amp; this.primaryAreaIdx &lt;= length1 ? new BlueprintArea[length1] : throw new Exception(“Corrupt Data”);<br>    for (int index = 0; index &lt; length1; ++index)<br>    {<br>      this.areas[index] = new BlueprintArea();<br>      this.areas[index].Import(r, this.version);<br>    }<br>    int length2 = r.ReadInt32();<br>    this.buildings = length2 &gt;= 0 &amp;&amp; length2 &lt;= 1048576 ? new BlueprintBuilding[length2] : throw new Exception(“Corrupt Data”);<br>    for (int index = 0; index &lt; length2; ++index)<br>    {<br>      this.buildings[index] = new BlueprintBuilding();<br>      this.buildings[index].Import(r, this.version);<br>    }<br>    for (int index = 0; index &lt; length2; ++index)<br>    {<br>      if (this.buildings[index].outputObj == null &amp;&amp; this.buildings[index].tempOutputObjIdx &gt;= 0)<br>        this.buildings[index].outputObj = this.buildings[this.buildings[index].tempOutputObjIdx];<br>      if (this.buildings[index].inputObj == null &amp;&amp; this.buildings[index].tempInputObjIdx &gt;= 0)<br>        this.buildings[index].inputObj = this.buildings[this.buildings[index].tempInputObjIdx];<br>    }<br>    this.DataRepair();<br>  }</p>
<p>  public void Export(BinaryWriter w)<br>  {<br>    this.version = 1;<br>    w.Write(this.version);<br>    w.Write(this.cursorOffset_x);<br>    w.Write(this.cursorOffset_y);<br>    w.Write(this.cursorTargetArea);<br>    w.Write(this.dragBoxSize_x);<br>    w.Write(this.dragBoxSize_y);<br>    w.Write(this.primaryAreaIdx);<br>    int num1 = this.areas != null ? this.areas.Length : 0;<br>    w.Write((byte) num1);<br>    for (int index = 0; index &lt; num1; ++index)<br>      this.areas[index].Export(w);<br>    int num2 = this.buildings != null ? this.buildings.Length : 0;<br>    w.Write(num2);<br>    for (int index = 0; index &lt; num2; ++index)<br>      this.buildings[index].Export(w);<br>  }</p>
<p>public StringBuilder ToBase64StringBuilder()<br>  {<br>    try<br>    {<br>      StringBuilder base64StringBuilder = new StringBuilder(1024);<br>      using (MemoryStream output = new MemoryStream())<br>      {<br>        using (BinaryWriter w = new BinaryWriter((Stream) output))<br>        {<br>          this.Export(w);<br>          output.Position = 0L;<br>          using (MemoryStream memoryStream = new MemoryStream())<br>          {<br>            using (GZipStream destination = new GZipStream((Stream) memoryStream, CompressionMode.Compress))<br>              output.CopyTo((Stream) destination);<br>            byte[] array = memoryStream.ToArray();<br>            base64StringBuilder.Append(this.headerStr);<br>            base64StringBuilder.Append(Convert.ToBase64String(array));<br>            string str = MD5F.Compute(base64StringBuilder.ToString());<br>            base64StringBuilder.Append(“\””);<br>            base64StringBuilder.Append(str);<br>            return base64StringBuilder;<br>          }<br>        }<br>      }<br>    }<br>    catch (Exception ex)<br>    {<br>      Debug.LogError((object) ex.ToString().Replace(“Exception”, “Excption”));<br>    }<br>    return (StringBuilder) null;<br>  }</p>
<p>public BlueprintDataIOError ContentFromBase64String(string strData)<br>  {<br>    try<br>    {<br>      int num1 = -1;<br>      int num2 = -1;<br>      for (int index = 0; index &lt; strData.Length; ++index)<br>      {<br>        if (strData[index] == ‘“‘)<br>        {<br>          num1 = index;<br>          break;<br>        }<br>      }<br>      if (num1 &lt; 0)<br>        return BlueprintDataIOError.DataCorruption;<br>      for (int index = strData.Length - 1; index &gt;= 0; —index)<br>      {<br>        if (strData[index] == ‘“‘)<br>        {<br>          num2 = index;<br>          break;<br>        }<br>      }<br>      if (num2 &lt; num1 + 32)<br>        return BlueprintDataIOError.DataCorruption;<br>      using (MemoryStream memoryStream1 = new MemoryStream(Convert.FromBase64String(strData.Substring(num1 + 1, num2 - num1 - 1))))<br>      {<br>        using (MemoryStream memoryStream2 = new MemoryStream())<br>        {<br>          using (GZipStream gzipStream = new GZipStream((Stream) memoryStream1, CompressionMode.Decompress))<br>            gzipStream.CopyTo((Stream) memoryStream2);<br>          memoryStream2.Position = 0L;<br>          using (BinaryReader r = new BinaryReader((Stream) memoryStream2))<br>            this.Import(r);<br>        }<br>      }<br>      return BlueprintDataIOError.OK;<br>    }<br>    catch (Exception ex)<br>    {<br>      Debug.LogError((object) (“Load Blueprint Error: \r\n” + ex.ToString().Replace(“Exception”, “Excption”)));<br>      return BlueprintDataIOError.DataCorruption;<br>    }<br>  }</p>
<p>public class BlueprintData<br>{<br>  public DateTime time;<br>  public string gameVersion;<br>  public string shortDesc;<br>  public string desc;<br>  public EIconLayout layout;<br>  public int icon0;<br>  public int icon1;<br>  public int icon2;<br>  public int icon3;<br>  public int icon4;<br>  public int cursorOffset_x;<br>  public int cursorOffset_y;<br>  public int cursorTargetArea;<br>  public int dragBoxSize_x;<br>  public int dragBoxSize_y;<br>  public int primaryAreaIdx;<br>  public BlueprintArea[] areas;<br>  public BlueprintBuilding[] buildings;<br>  private List<BlueprintBuilding> _tmp_buidings = new List<BlueprintBuilding>();<br>  private List<BlueprintBuilding> _del_buidings = new List<BlueprintBuilding>();<br>  private int version;</p>
<p>  public bool isValid =&gt; this.primaryAreaIdx &gt;= 0 &amp;&amp; this.buildings != null &amp;&amp; this.areas != null &amp;&amp; this.areas.Length != 0;</p>
<p>  public bool isEmpty =&gt; this.buildings == null || this.buildings.Length == 0;</p>
<p>  public static bool IsNullOrEmpty(BlueprintData blueprint) =&gt; blueprint == null || !blueprint.isValid || blueprint.buildings.Length == 0;</p>
<p>  public string headerStr =&gt; “BLUEPRINT:0,” + ((int) this.layout).ToString() + “,” + this.icon0.ToString() + “,” + this.icon1.ToString() + “,” + this.icon2.ToString() + “,” + this.icon3.ToString() + “,” + this.icon4.ToString() + “,0,” + this.time.Ticks.ToString() + “,” + this.gameVersion + “,” + this.shortDesc.Escape() + “,” + this.desc.Escape() + “\””;</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/03/23/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/unity%E5%8F%8D%E7%BC%96%E8%AF%91/" data-id="cl403sxrn002hf8vu3wl565w6" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-代码实战/中国象棋unity" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/03/23/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/%E4%B8%AD%E5%9B%BD%E8%B1%A1%E6%A3%8Bunity/" class="article-date">
  <time class="dt-published" datetime="2022-03-22T18:35:37.513Z" itemprop="datePublished">2022-03-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="用-Unity-编写象棋游戏"><a href="#用-Unity-编写象棋游戏" class="headerlink" title="用 Unity 编写象棋游戏"></a>用 Unity 编写象棋游戏</h1><p>基本概述及操作方法</p>
<p>打开 Scenes 文件夹中的 Main 场景。你会看到一个表示棋盘的 Board 对象和一个 GameManager 对象。这些对象都已经绑定了脚本。</p>
<ul>
<li>Prefabs: 包含了棋盘、 棋子、和移动过程中的指示方块。</li>
<li>Materials: 包含了棋盘、棋子和瓦片的材质。</li>
<li>Scripts: 包含了在结构视图中已经绑定到对象中的组件。</li>
<li>Board: 记录棋子的可视化状态。这个组件还会处理每颗棋子的高亮状态。</li>
<li>Geometry.cs: 工具类，负责处理行列转换和 Vector3 点。</li>
<li>wwwwPlayer.cs: 记录玩家的棋子，玩家手执的棋子。保存玩w家棋子移动的方向，比如小兵。</li>
<li>Piece.cs: 一个基类，定义了所有实例化的棋子对象的枚举。它还包含确定游戏中有效移动的逻辑。</li>
<li>GameManager.cs: 存储游戏逻辑，比如允许的移动，游戏一开始时棋子的位置等。它是一个单例对象，所以其他类很容易调用它。</li>
</ul>
<p>GameManager 的 pieces 保存了一个 2D 数组，记录了棋子在棋盘上的位置。可以看一下 AddPiece、PieceAtGrid 和 GridForPiece 的逻辑。</p>
<p>进入试玩模式，你会看到一个棋盘，棋子准备好后就可以下棋了。</p>
<p>文件结构</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/03/23/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/%E4%B8%AD%E5%9B%BD%E8%B1%A1%E6%A3%8Bunity/" data-id="cl403sxro002jf8vu52w7h6vl" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-小项目模板/pvz/植物大战僵尸" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/03/14/%E5%B0%8F%E9%A1%B9%E7%9B%AE%E6%A8%A1%E6%9D%BF/pvz/%E6%A4%8D%E7%89%A9%E5%A4%A7%E6%88%98%E5%83%B5%E5%B0%B8/" class="article-date">
  <time class="dt-published" datetime="2022-03-14T12:32:30.314Z" itemprop="datePublished">2022-03-14</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="1引入需要的模块"><a href="#1引入需要的模块" class="headerlink" title="1引入需要的模块"></a>1引入需要的模块</h1><p>import pygame<br>import time<br>import random</p>
<h1 id="1配置图片地址"><a href="#1配置图片地址" class="headerlink" title="1配置图片地址"></a>1配置图片地址</h1><p>IMAGE_PATH = ‘D:/死亡笔记/开发代码/自制游戏/植物大战僵尸/resources/graphics/‘</p>
<h1 id="1设置页面宽高"><a href="#1设置页面宽高" class="headerlink" title="1设置页面宽高"></a>1设置页面宽高</h1><p>scrrr_width=1000<br>scrrr_height =600</p>
<h1 id="1创建控制游戏结束的状态"><a href="#1创建控制游戏结束的状态" class="headerlink" title="1创建控制游戏结束的状态"></a>1创建控制游戏结束的状态</h1><p>GAMEOVER = False</p>
<h1 id="2-创建关数，剩余分数，钱数"><a href="#2-创建关数，剩余分数，钱数" class="headerlink" title="2 创建关数，剩余分数，钱数"></a>2 创建关数，剩余分数，钱数</h1><p>shaoguan = 1<br>remnant_score = 100</p>
<h1 id="3-创建地图类，初始化地图和坐标"><a href="#3-创建地图类，初始化地图和坐标" class="headerlink" title="3.创建地图类，初始化地图和坐标"></a>3.创建地图类，初始化地图和坐标</h1><h1 id="3-创建地图类"><a href="#3-创建地图类" class="headerlink" title="3 创建地图类"></a>3 创建地图类</h1><p>class Map():</p>
<pre><code>#3 初始化地图
def __init__(self, x, y,map_path):
    self.position = [x, y]
    # 是否能够种植
    self.can_grow = True    
    self.image = pygame.image.load(map_path)
    #3 存储所有地图坐标点
    self.map_points_list = []
    #3 存储所有的地图块
    self.map_list = []

    #3 加载地图
def load_map(self,mainGame):
    mainGame.blit(self.image,self.position)
    if self.position[0]&gt;-200:
        self.position[0]-=10
</code></pre><p>​<br>​        #3 初始化坐标点<br>​    def init_plant_points(self, mainGame):<br>​        for y in range(1, 7):<br>​            points = []<br>​            for x in range(10):<br>​                point = [x<em>80+50, y</em>90+10]<br>​                pygame.draw.rect(mainGame,[0,0,0],[point[0],point[1],10,10],1)<br>​                points.append(point)<br>​            self.map_points_list.append(points)<br>​            #print(“MainGame.map_points_list”, self.map_points_list)</p>
<h1 id="4-创建植物类"><a href="#4-创建植物类" class="headerlink" title="4 创建植物类"></a>4 创建植物类</h1><p>class Plant(pygame.sprite.Sprite):<br>​    def <strong>init</strong>(self):<br>​        super(Plant, self).<strong>init</strong>()<br>​        self.live=True<br>​        self.num=0<br>​        self.image=[]<br>​    # 加载图片<br>​    def load_image(self,mainGame):<br>​        if self.live==True:<br>​            mainGame.window.blit(self.image[self.num],0,0)<br>​            self.num+=1<br>​            if self.num&gt;=len(self.image):<br>​                self.num=0<br>​            </p>
<h1 id="5-向日葵类"><a href="#5-向日葵类" class="headerlink" title="5 向日葵类"></a>5 向日葵类</h1><p>class Sunflower(Plant):<br>​    def <strong>init</strong>(self,x,y):<br>​        super(Sunflower, self).<strong>init</strong>()<br>​        for i in range(1,18):<br>​            self.image.append(pygame.image.load(IMAGE_PATH+’Plants/SunFlower/SunFlower_’+str(i)+’.png’))<br>​        self.rect = self.image[0].get_rect()<br>​        self.x = x<br>​        self.y = y<br>​        self.price = 50<br>​        self.hp = 100<br>​        #5 时间计数器<br>​        self.time_count = 0<br>​    # 加载图片<br>​    def load_image(self,mainGame):<br>​        if self.live==True:<br>​            self.produce_sun_number(mainGame)<br>​            mainGame.window.blit(self.image[self.num],(self.x,self.y))<br>​            self.num+=1<br>​            if self.num&gt;=len(self.image):<br>​                self.num=0<br>​    #5 功能：生成阳光<br>​    def produce_sun_number(self,mainGame):<br>​        self.time_count += 1<br>​        if self.time_count == 200:<br>​            mainGame.sun_number += 25<br>​            self.time_count = 0</p>
<h1 id="6-豌豆射手类"><a href="#6-豌豆射手类" class="headerlink" title="6 豌豆射手类"></a>6 豌豆射手类</h1><p>class PeaShooter(Plant):<br>    def <strong>init</strong>(self,x,y):<br>        super(PeaShooter, self).<strong>init</strong>()<br>        for i in range(13):<br>            self.image.append(pygame.image.load(IMAGE_PATH+’Plants/Peashooter/Peashooter_’+str(i)+’.png’))<br>        self.rect = self.image[0].get_rect()<br>        self.x = x<br>        self.y = y<br>        self.price = 50<br>        self.hp = 100</p>
<pre><code>    #6 发射计数器
    self.shot_count = 0
# 加载图片
def load_image(self,mainGame):
    if self.live==True:
        self.shot(mainGame)
        mainGame.window.blit(self.image[self.num],(self.x,self.y))
        self.num+=1
        if self.num&gt;=len(self.image):
            self.num=0

#6 增加射击方法
def shot(self,mainGame):
    #6 记录是否应该射击
    should_fire = True
    for zombie in mainGame.zombie_list:
        if zombie.rect.y == self.rect.y and zombie.rect.x &lt; 800 and zombie.rect.x &gt; self.rect.x:
            should_fire = True
    #6 如果活着
    if self.live and should_fire:
        self.shot_count += 1
        # 计数器到25发射一次
        if self.shot_count == 25: 
            peabullet = PeaBullet(self)
            #6 将子弹存储到子弹列表中
            mainGame.peabullet_list.append(peabullet)
            self.shot_count = 0
</code></pre><h1 id="7-豌豆子弹类"><a href="#7-豌豆子弹类" class="headerlink" title="7 豌豆子弹类"></a>7 豌豆子弹类</h1><p>class PeaBullet(pygame.sprite.Sprite):<br>    def <strong>init</strong>(self,peashooter):<br>        self.live = True<br>        self.image = pygame.image.load(IMAGE_PATH+’Bullets/PeaNormal/PeaNormal_0.png’)<br>        self.damage = 50<br>        self.speed  = 10<br>        self.rect = self.image.get_rect()<br>        self.x = peashooter.x + 35<br>        self.y = peashooter.y + 5</p>
<pre><code>def move_bullet(self):
    #7 在屏幕范围内，实现往右移动
    if self.x &lt; scrrr_width:
        self.x += self.speed
    else:
        self.live = False
def load_image(self,mainGame):
    mainGame.window.blit(self.image,(self.x,self.y))            
</code></pre><h1 id="1主程序"><a href="#1主程序" class="headerlink" title="1主程序"></a>1主程序</h1><p>class MainGame():<br>    def  <strong>init</strong>(self,map_path):<br>        self.poss=(0,0)</p>
<pre><code>    #1初始化窗口
    self.init_window(map_path)
    self.map_class =  Map(0,0,map_path)
    self.current_times=1
    self.sun_number=100
    self.check_id=-1
    #4 存储所有植物的列表
    self.plants_list = []
    #4 存储所有植物lan的列表
    self.ChooserBackground=pygame.image.load(IMAGE_PATH+&quot;Screen/ChooserBackground.png&quot;)
    self.plants_lan_list = [
        pygame.transform.scale(pygame.image.load(IMAGE_PATH+&quot;Cards/card_sunflower.png&quot;),(50, 70)),
        pygame.transform.scale(pygame.image.load(IMAGE_PATH+&quot;Cards/card_peashooter.png&quot;),(50, 70))]
    self.plants_lan_move_list = [
        pygame.transform.scale(pygame.image.load(IMAGE_PATH+&quot;Cards/card_sunflower_move.png&quot;),(50, 70)),
        pygame.transform.scale(pygame.image.load(IMAGE_PATH+&quot;Cards/card_peashooter_move.png&quot;),(50, 70))]
    #4 存储所有僵尸的列表
    self.zombie_list=[]
    self.peabullet_list=[]

 #1加载游戏窗口
def init_window(self,map_path):
    #1调用显示模块的初始化
    pygame.display.init()
    #1创建窗口
    self.window = pygame.display.set_mode([scrrr_width,scrrr_height])  #
#1开始游戏
def start_game(self):
    #1只要游戏没结束，就一直循环
    while not GAMEOVER:
        #1渲染白色背景
        self.window.fill((255, 255, 255))
        self.map_class.load_map(self.window)

        if self.map_class.position[0]&lt;=-200:
            #按键区块
            self.deal_events()
            #逻辑区块
            for i in range(len(self.peabullet_list)):
                self.peabullet_list[i].move_bullet()
            #渲染区块
            self.load_plant_column()
            self.window.blit(self.draw_text(str(self.sun_number), 15, (0,0,0)), (60, 63))
            self.map_class.init_plant_points(self.window)
            if self.check_id!=-1:
                self.window.blit(self.plants_lan_move_list[self.check_id],[self.poss[0]-30,self.poss[1]-35])
            for i in range(len(self.plants_list)-1,-1,-1):
                if self.plants_list[i].live == False:
                    del self.plants_list[i]
                    continue
                self.plants_list[i].load_image(self)
            for i in range(len(self.peabullet_list)-1,-1,-1):

                if self.peabullet_list[i].live == False:
                    print(i)
                    del self.peabullet_list[i]
                    continue
                self.peabullet_list[i].load_image(self)

        #1实时更新
        pygame.display.update()

        self.current_times=self.current_times+1
        if self.current_times%250==0:
            self.sun_number=self.sun_number+25
        time.sleep(0.05)
#2.文本绘制，创建要动态改变的属性，渲染的位置
#2 文本绘制
def draw_text(self, content, size, color):
    pygame.font.init()
    font = pygame.font.SysFont(&#39;kaiti&#39;, size)
    text = font.render(content, True, color)
    return text
def load_plant_column(self):
    self.window.blit(self.ChooserBackground,[30,0])
    wid=55
    for i in range(len(self.plants_lan_list)):
        self.window.blit(self.plants_lan_list[i],[110+wid*i,10])
#2 加载帮助提示
def load_help_text(self):
    text1 = self.draw_text(&#39;1.按左键创建向日葵 2.按右键创建豌豆射手&#39;, 26, (255, 0, 0))
    self.window.blit(text1, (50, 70))
    #2 渲染的文字和坐标位置
    self.window.blit(self.draw_text(&#39;当前钱数$: &#123;&#125;&#39;.format(self.sun_number), 26, (255, 0, 0)), (200,60))
#6 加载植物处理
def load_plants(self):
    for plant in self.plants_list:
        #6 优化加载植物的处理逻辑
        if plant.live:
            if isinstance(plant, Sunflower):
                plant.load_image(self)
                plant.produce_sun_number(self)
            elif isinstance(plant, PeaShooter):
                plant.load_image(self)
                plant.shot(self)
        else:
            self.plants_list.remove(plant)
#8事件处理
def deal_events(self):
    #8 获取所有事件
    eventList = pygame.event.get()
    #8 遍历事件列表，判断
    for e in eventList:
        if e.type == pygame.QUIT:
            exit()
        elif e.type == pygame.MOUSEBUTTONDOWN:
            # print(&#39;按下鼠标按键&#39;)
            if e.pos[1]&gt;10 and e.pos[1]&lt;80:
                if e.pos[0]&gt;110 and e.pos[0]&lt;110+55*(len(self.plants_lan_list)):
                    self.check_id=int((e.pos[0]-110)/55)
                    self.poss=e.pos
                else:
                    self.check_id=-1
            elif e.pos[1]&gt;100 and e.pos[1]&lt;550 and self.check_id!=-1:
                if e.pos[0]&gt;50 and e.pos[0]&lt;770:
                    if self.check_id==0 and self.sun_number&gt;=50:
                        self.sun_number-=15
                        self.plants_list.append(Sunflower((((int)((e.pos[0]-50)/80))*80+50),((int)(((e.pos[1]-100)/90))*90)+100))
                    elif self.check_id==1and self.sun_number&gt;=100:
                        self.sun_number-=100
                        self.plants_list.append(PeaShooter((((int)((e.pos[0]-50)/80))*80+50),((int)(((e.pos[1]-100)/90))*90)+100))
                    self.check_id=-1
                else:
                    self.check_id=-1
            else:
                self.check_id=-1

        elif e.type == pygame.MOUSEMOTION:
            if self.check_id!=-1:
                self.poss=e.pos
        # print(e.button)#左键1  按下滚轮2 上转滚轮为4 下转滚轮为5  右键 3
        &#39;&#39;&#39;
        x = e.pos[0] // 80
        y = e.pos[1] // 80
        print(x, y)
        map = MainGame.map_list[y - 1][x]
        print(map.position)
        #8 增加创建时候的地图装填判断以及金钱判断
        if e.button == 1:
            if map.can_grow and MainGame.money &gt;= 50:
                sunflower = Sunflower(map.position[0], map.position[1])
                MainGame.plants_list.append(sunflower)
                print(&#39;当前植物列表长度:&#123;&#125;&#39;.format(len(MainGame.plants_list)))
                map.can_grow = False
                MainGame.money -= 50
        elif e.button == 3:
            if map.can_grow and MainGame.money &gt;= 50:
                peashooter = PeaShooter(map.position[0], map.position[1])
                MainGame.plants_list.append(peashooter)
                print(&#39;当前植物列表长度:&#123;&#125;&#39;.format(len(MainGame.plants_list)))
                map.can_grow = False
                MainGame.money -= 50

                #8 调用事件处理的方法
                self.deal_events()&#39;&#39;&#39;
</code></pre><h1 id="1启动主程序"><a href="#1启动主程序" class="headerlink" title="1启动主程序"></a>1启动主程序</h1><p>if <strong>name</strong> == ‘<strong>main</strong>‘:<br>​    game = MainGame(IMAGE_PATH+”/Items/Background/Background_0.jpg”)<br>​    game.start_game()</p>
<p>植物可以自动设子弹以后 下一步 开始创建僵尸类</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/03/14/%E5%B0%8F%E9%A1%B9%E7%9B%AE%E6%A8%A1%E6%9D%BF/pvz/%E6%A4%8D%E7%89%A9%E5%A4%A7%E6%88%98%E5%83%B5%E5%B0%B8/" data-id="cl403sxsq0053f8vuctmm9qpe" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-代码实战/四国象棋ai" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/03/10/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/%E5%9B%9B%E5%9B%BD%E8%B1%A1%E6%A3%8Bai/" class="article-date">
  <time class="dt-published" datetime="2022-03-10T11:42:59.548Z" itemprop="datePublished">2022-03-10</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        
      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/03/10/%E4%BB%A3%E7%A0%81%E5%AE%9E%E6%88%98/%E5%9B%9B%E5%9B%BD%E8%B1%A1%E6%A3%8Bai/" data-id="cl403sxro002kf8vu8zlr9muv" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-炉石传说/第一步开发游戏选择界面 - 副本" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/03/08/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%BC%80%E5%8F%91%E6%B8%B8%E6%88%8F%E9%80%89%E6%8B%A9%E7%95%8C%E9%9D%A2%20-%20%E5%89%AF%E6%9C%AC/" class="article-date">
  <time class="dt-published" datetime="2022-03-08T12:52:04.204Z" itemprop="datePublished">2022-03-08</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="战棋游戏开发"><a href="#战棋游戏开发" class="headerlink" title="战棋游戏开发"></a><strong>战棋游戏开发</strong></h1><h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><ul>
<li>该系列文章为本人开发战棋游戏的回顾总结。</li>
</ul>
<h2 id="开发工具"><a href="#开发工具" class="headerlink" title="开发工具"></a>开发工具</h2><h3 id="下面是游戏开发使用的引擎和框架。"><a href="#下面是游戏开发使用的引擎和框架。" class="headerlink" title="下面是游戏开发使用的引擎和框架。"></a>下面是游戏开发使用的引擎和框架。</h3><ul>
<li>游戏引擎: Unity3D</li>
<li>游戏框架: GameFramework</li>
</ul>
<p>游戏源码</p>
<h2 id="系统整体结构"><a href="#系统整体结构" class="headerlink" title="系统整体结构"></a>系统整体结构</h2><ul>
<li>系统整体结构<ul>
<li>战棋战斗系统<ul>
<li>战场地图模块</li>
<li>战斗单位模块</li>
<li>战斗流程模块</li>
</ul>
</li>
<li>战斗编辑器系统<ul>
<li>地图数据编辑器</li>
<li>战斗数据编辑器</li>
</ul>
</li>
<li>其他辅助功能模块<h3 id="战场地图模块"><a href="#战场地图模块" class="headerlink" title="战场地图模块"></a>战场地图模块</h3></li>
</ul>
</li>
<li>战场地图设置为六边形网格地图, 使用字典保存地图网格单元数据。</li>
<li>战场生成步骤:<ul>
<li>反序列化战场地图数据 - 借助newtonsoft.json</li>
<li>战场地图渲染 - 借助Unity组件tilemap<h3 id="人物模型搭建"><a href="#人物模型搭建" class="headerlink" title="人物模型搭建"></a>人物模型搭建</h3><h4 id="首先我们先把玩家导入进去"><a href="#首先我们先把玩家导入进去" class="headerlink" title="首先我们先把玩家导入进去"></a>首先我们先把玩家导入进去</h4>现在市面上公开的模型好多都是pmx，我们要先进行转码成fbx，这就需要用到blender<br>下载网址：<br><a target="_blank" rel="noopener" href="https://www.blender.org/download/lts/2-83/">Blender 2.83 LTS — blender.org</a><br><a href="https://codeload.[github](https://so.csdn.net/so/search?q=github&amp;spm=1001.2101.3001.7020).com/GiveMeAllYourCats/cats-blender-plugin/zip/master">https://codeload.[github](https://so.csdn.net/so/search?q=github&amp;spm=1001.2101.3001.7020).com/GiveMeAllYourCats/cats-blender-plugin/zip/master</a><br>三、Blender安装好和下载好插件之后，打开Blender安装插件<br>依次点击  编辑-&gt;偏好设置-&gt;插件-&gt;安装  选在刚才下好的插件压缩包进行安装。<br><img src="d9f28627a058449caabd869cc4048f85.png" alt="img"><br>四、安装后打开软件右上角的小箭头<br><img src="61938cf1e62f486eb01ce5dbe01cb8c7.png" alt="img"><br>五、选择CAST选项，选择MMD，然后选择需要转换的PMX文件<br><img src="a3696354ff4d451cbe00b919097c1392.png" alt="img"><br>六、打开模型后，选择杂项-&gt;Shadeless<br><img src="81cacdddabf042338a0a93e91702c002.png" alt="img"><br>七、回到CAST选项，修改Fix Model（点击Fix Model右边的把手）<br><img src="6e5be01e0fc546019f97e249e8ea719e.png" alt="img"><br>八 、修改完成后点击Fix Model，等待数十秒。<br><img src="4b2e79dad1b34385933d0a63e8dab15a.png" alt="img"><br>九、完成后，就可以点击导出模型了（Export Model）<br><img src="7f14c15f565a4113a3ae2570c096d00c.png" alt="img"><br>十、导出成FBX格式后，先把相关贴图文件夹先导入/拖入Unity，之后才能把FBX模型导入/拖入。否则导入的会只是一个白模。<br>十一、正常导入后会如红框中显示的没有相关 材质，这时需要点击Extract Materials，之后会自动匹配上。<br><img src="cc92ad6c143f41d781dcc881b3e17781.png" alt="img"><img src="26c3571b72b74b94958f110e2eece9ae.png" alt="img"><br>十三、至此已经完成导入，如模型出现异常请先检查相关材质是否已经先导入了，并且和原来PMX模型相对目录结构一致。 已导入的话，将材质的渲染模式改成Cutout。<br><img src="81460e4a6e244b5d86a963070ef2a252.png" alt="img"></li>
</ul>
</li>
</ul>
<p>一、给人物模型添加对应的动作模型</p>
<p><img src="11.png" alt="11"></p>
<p>二、新建动作控制器</p>
<p><img src="新建动作控制器-1651409549478.png" alt="新建动作控制器"></p>
<p>三、初始化地形</p>
<p><img src="初始化地形.png" alt="初始化地形"></p>
<p><img src="初始化地形 (2" alt="初始化地形 (2)">.png)</p>
<p>编写摄像头移动脚本</p>
<p>补充下基础知识</p>
<h1 id="Unity3D入门篇——Transform类"><a href="#Unity3D入门篇——Transform类" class="headerlink" title="Unity3D入门篇——Transform类"></a>Unity3D入门篇——Transform类</h1><p><img src="reprint.png" alt="img"></p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/a_little_a_day">a_little_a_day</a><img src="newCurrentTime2.png" alt="img">于 2018-03-01 11:30:30 发布<img src="articleReadEyes2.png" alt="img">3533<img src="tobarCollect2.png" alt="img"> 收藏 6</p>
<p><strong>Unity3D入门篇——Transform类</strong></p>
<p>Transform组件是Unity3D的重点之一，主要用于控制物体的旋转、移动、缩放。那么接下来我们将详细学习下Transform类所包含的成员变量和<a target="_blank" rel="noopener" href="https://so.csdn.net/so/search?q=成员函数&amp;spm=1001.2101.3001.7020">成员函数</a>。</p>
<p><strong>一、成员变量</strong></p>
<p><strong>position：在世界空间坐标transform的位置。<br>localPosition：相对于父级的变换的位置。如果该变换没有父级，那么等同于Transform.position。<br>eulerAngles：世界坐标系中的旋转（欧拉角）。<br>localEulerAngles：相对于父级的变换旋转角度。<br>right：世界坐标系中的右方向。（世界空间坐标变换的红色轴。也就是x轴。）<br>up：世界坐标系中的上方向。（在世界空间坐标变换的绿色轴。也就是y轴。）<br>forward：世界坐标系中的前方向。（在世界空间坐标变换的蓝色轴。也就是z轴。）<br>rotation：世界坐标系中的旋转（四元数）。<br>localRotation：相对于父级的变换旋转角度。<br>localScale：相对于父级的缩放比例。<br>parent：父对象Transform组件。<br>worldToLocalMatrix：矩阵变换的点从世界坐标转为自身坐标（只读）。<br>localToWorldMatrix：矩阵变换的点从自身坐标转为世界坐标（只读）。<br>root：对象层级关系中的根对象的Transform组件。<br>childCount：子对象数量。<br>lossyScale：全局缩放比例（只读）。
</strong></p>
<p><strong>二、成员函数：</strong></p>
<p><strong>1、LookAt函数</strong></p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> <strong>void</strong> LookAt(Transform target) </li>
<li><strong>public</strong> <strong>void</strong> LookAt(Vector3 worldPosition); </li>
<li><strong>public</strong> <strong>void</strong> LookAt(Vector3 worldPosition, Vector3 worldUp = Vector3.up); </li>
<li><strong>public</strong> <strong>void</strong> LookAt(Transform target, Vector3 worldUp = Vector3.up); </li>
</ol>
<p>旋转物体，使物体的z轴指向target/worldPosition，对于worldUp的描述是，在完成上面的旋转之后，继续旋转自身，使得当前对象的正y轴朝向与worldUp所指向的朝向一致。</p>
<p>这里的朝向一致指的是新旋转后的y轴与worldUp在该对象初次旋转后的xy平面上的投影向量一致。之所以取投影是因为第一次旋转使物体的z轴指向target/worldPosition后，此时的worldUp向量可能不在xy平面上，要在z轴指向target/worldPosition前提下是y轴朝向与worldUp一致，只能取worldUp在xy平面上的投影。</p>
<p>注意：使用worldPosition向量时要注意方向，一定是target-transform.position，顺序反了会使物体背向目标；若使用Transform作为参数，则不必注意。默认情况下，worldUp是Vector3.up（世界坐标系下的y轴）</p>
<p><strong>2、Rotate函数</strong></p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> <strong>void</strong> Rotate(Vector3 eulerAngles); </li>
<li><strong>public</strong> <strong>void</strong> Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self); </li>
<li><strong>public</strong> <strong>void</strong> Rotate(<strong>float</strong> xAngle, <strong>float</strong> yAngle, <strong>float</strong> zAngle); </li>
<li><strong>public</strong> <strong>void</strong> Rotate(<strong>float</strong> xAngle, <strong>float</strong> yAngle, <strong>float</strong> zAngle, Space relativeTo = Space.Self); </li>
</ol>
<p>旋转一个欧拉角度，它按照zxy的顺序进行旋转，默认情况下局部坐标系下Space.Self。</p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> <strong>void</strong> Rotate(Vector3 axis, <strong>float</strong> angle);       </li>
<li><strong>public</strong> <strong>void</strong> Rotate(Vector3 axis, <strong>float</strong> angle,Space relativeTo = Space.Self); </li>
</ol>
<p>绕axis轴旋转angle角度，默认情况下局部坐标系下Space.Self。</p>
<p><strong>transform.rotation和Rotate有个区别：</strong></p>
<p>Rotate()方法是：旋转多少度。在原有的基础上累加，即旋转了多少角度。又旋转了多少角度，是在原有的基础上在旋转</p>
<p>rotation属性是：旋转到某个角度，就是是在update中每帧都执行。但每次旋转到的角度都是5，所以是旋转到5度。一直都是</p>
<p>比如你只想让他旋转到多少, 用rotation; 假如想让他一直转,可以用Rotate</p>
<p>rotation直接改变了数值, 以达到旋转效果</p>
<p>Rotate应用一个的旋转角度每秒1度慢慢的旋转物体</p>
<p>当然:rotation()还可以通过插值旋转</p>
<p><strong>3、TransformDirection函数</strong></p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> Vector3 TransformDirection(Vector3 direction); </li>
<li><strong>public</strong> Vector3 TransformDirection(<strong>float</strong> x, <strong>float</strong> y, <strong>float</strong> z); </li>
</ol>
<p>从自身坐标到世界坐标变换方向（这个强调的是方向）这个操作不会受到变换的缩放和位置的影响。返回的向量与direction有同样的长度</p>
<p><strong>4、TransformPoint函数</strong></p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> Vector3 TransformPoint(Vector3 position); </li>
<li><strong>public</strong> Vector3 TransformPoint(<strong>float</strong> x, <strong>float</strong> y, <strong>float</strong> z); </li>
</ol>
<p>变换位置从自身坐标到世界坐标。注意，返回位置受缩放影响</p>
<p><strong>5、TransformVector函数</strong></p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> Vector3 TransformVector(Vector3 vector); </li>
<li><strong>public</strong> Vector3 TransformVector(<strong>float</strong> x, <strong>float</strong> y, <strong>float</strong> z); </li>
</ol>
<p>变换一个向量从局部坐标空间到世界坐标空间。这个操作不受变换位置的影响，但是受缩放的影响</p>
<p><strong>6、Translate函数</strong></p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> <strong>void</strong> Translate(Vector3 translation); </li>
<li><strong>public</strong> <strong>void</strong> Translate(Vector3 translation, Space relativeTo = Space.Self); </li>
</ol>
<p>沿着translation方向移动translation向量长度的距离,如果relativeTo留空或者设置为Space.Self，移动被应用相对于自身坐标系</p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> <strong>void</strong> Translate(<strong>float</strong> x, <strong>float</strong> y, <strong>float</strong> z); </li>
<li><strong>public</strong> <strong>void</strong> Translate(<strong>float</strong> x, <strong>float</strong> y, <strong>float</strong> z, Space relativeTo = Space.Self); </li>
</ol>
<p>移动变换由x沿着x轴，y沿着y轴，z沿着z轴。如果relativeTo留空或者设置为Space.Self，移动被应用相对于自身坐标系</p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><strong>public</strong> <strong>void</strong> Translate(Vector3 translation, Transform relativeTo);   </li>
<li><strong>public</strong> <strong>void</strong> Translate(<strong>float</strong> x, <strong>float</strong> y, <strong>float</strong> z, Transform relativeTo); </li>
</ol>
<p>第一个参数的解释跟前面的一样，重点在移动relativeTo，解释为被应用相对于（relativeTo :Transform）的自身坐标系统。日光相对于为null，则移动被应用相对于世界坐标系统</p>
<p><strong>[csharp]</strong> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">view plain</a> <a target="_blank" rel="noopener" href="http://blog.csdn.net/u014086857/article/details/53091268#">copy</a></p>
<ol>
<li><p>例子： </p>
</li>
<li><p><strong>void</strong> Update() </p>
</li>
<li><p>{ </p>
</li>
<li><p>//相对于摄像机每秒1单位向右移动物体 </p>
</li>
<li><p>transform.Translate(Vector3.right * Time.deltaTime, Camera.main.transform); </p>
</li>
<li><p>} </p>
</li>
</ol>
<p>第一步 编写接受键盘信息的方法<br>    void Update()<br>    {<br>        if (Input.geyKeyDown(KeyCode.A))<br>        {<br>            Debug.Log(“A”);<br>            //gameObject.transform.position;<br>        }<br>        if (Input.geyKeyDown(KeyCode.S))<br>        {<br>            Debug.Log(“S”);<br>            //gameObject.transform.position;<br>        }<br>        if (Input.geyKeyDown(KeyCode.D))<br>        {<br>            Debug.Log(“D”);<br>            //gameObject.transform.position;<br>        }<br>        if (Input.geyKeyDown(KeyCode.W))<br>        {<br>            Debug.Log(“W”);<br>            //gameObject.transform.position;<br>        }<br>    }</p>
<p>第二步 添加摄像机位移方法</p>
<p>补充知识：</p>
<pre><code>    Vector3.forward                (前方)
    Vector3.up                        (上方)
    Vector3.right                   （右方）

    Vector3.back                     (后方)
    Vector3.left                        (左方）
    Vector3.down                    (下方)
void Update()
&#123;
    if (Input.GetKey(KeyCode.A))
    &#123;
        Debug.Log(&quot;A&quot;);
        this.transform.Translate(Vector3.left * Time.deltaTime * speed);
        //gameObject.transform.position;
    &#125;
    if (Input.GetKey(KeyCode.S))
    &#123;
        Debug.Log(&quot;S&quot;);
        this.transform.Translate(Vector3.back * Time.deltaTime * speed);
        //gameObject.transform.position;
    &#125;
    if (Input.GetKey(KeyCode.D))
    &#123;
        Debug.Log(&quot;d&quot;);
        this.transform.Translate(Vector3.right*Time.deltaTime*speed);
    &#125;
    if (Input.GetKey(KeyCode.W))
    &#123;
        Debug.Log(&quot;W&quot;);
        this.transform.Translate(Vector3.forward * Time.deltaTime * speed);
        //gameObject.transform.position;
    &#125;
&#125;
</code></pre><p>然后添加可以在鼠标光标位置放置角色的方法</p>
<pre><code>    if (Input.GetMouseButtonUp(0))
    &#123;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray, out hit))
        &#123;
            Debug.Log(hit.point);
            Instantiate(people, hit.point, people.transform.rotation);
        &#125;
    &#125;
</code></pre><p>编写角色攻击方法</p>
<p>角色攻击一般分为近战和远程，我们先实现远程的角色</p>
<p>第一步 先实现点击键盘e键对应角色发射子弹的方法</p>
<p>public class PersonShut : MonoBehaviour<br>{<br>    // 射击物<br>    public GameObject ShutObject;<br>    // Start is called before the first frame update<br>    /// <summary>
    /// 子弹持续时间
    /// </summary><br>    private int time;<br>    // Start is called before the first frame update<br>    void Start()<br>    {<br>        Destroy(ShutObject, time);<br>    }</p>
<pre><code>void Update()
&#123;
    if (Input.GetKeyUp(KeyCode.E))
    &#123;
        Debug.Log(&quot;发射&quot;);
        var people = this.transform.rotation.eulerAngles;
        var shutPosition = this.transform.position;
        shutPosition += new Vector3(
            2 * (float)Math.Sin(people.y / 180 * Math.PI),
            10,
            2 * (float)Math.Cos(people.y / 180 * Math.PI));
        //shutPosition+= this.transform.rotation * 3;
        Instantiate(ShutObject, shutPosition, this.transform.rotation);
    &#125;
&#125;
</code></pre><p>}</p>
<p>第二步 编写子弹脚本</p>
<p>public class ShutBomb : MonoBehaviour<br>{<br>    public GameObject Person;<br>    // 射击物<br>    public GameObject ShutObject;<br>    /// <summary>
    /// 子弹持续时间
    /// </summary><br>    public int time;<br>    public int forceNum;<br>    // Start is called before the first frame update<br>    void Start()<br>    {<br>        Vector3 angle = Person.transform.rotation.eulerAngles;<br>        Vector3 Force = new Vector3(forceNum <em> (float)Math.Sin(angle.y / 180 </em> Math.PI), 2, forceNum <em> (float)Math.Cos(angle.y / 180 </em> Math.PI));<br>        ShutObject.GetComponent<Rigidbody>().AddForce(Force, ForceMode.VelocityChange);<br>    }<br>    void OnBecameInvisible()<br>    {<br>        if (this.enabled)<br>        {<br>            Destroy(this.gameObject);<br>        }<br>    }<br>    // Update is called once per frame<br>    void Update()<br>    {<br>    }<br>}</p>
<p>编写子弹消失方法</p>
<p>public class DelectShut : MonoBehaviour<br>{<br>    public GameObject shut;<br>    // Start is called before the first frame update<br>    void Start()<br>    {<br>        Destroy(shut, 5);<br>    }</p>
<pre><code>// Update is called once per frame
void Update()
&#123;

&#125;
</code></pre><p>}</p>
<p>然后将其挂载在子弹上</p>
<p><img src="销毁子弹.png" alt="销毁子弹"></p>
<p>增添子弹击中目标爆炸方法</p>
<p>在子弹预制体上选择Is Trigger选项</p>
<p><img src="istag.png" alt="istag"></p>
<p>下一步 设计场景地图</p>
<p>第一步 创建单个地图元</p>
<p><img src="地图障碍物创建.png" alt="地图障碍物创建"></p>
<p>添加贴图</p>
<p><img src="image-20220515191812531.png" alt="image-20220515191812531"></p>
<p><em>A在此球体上显示为反射的山脉场景立方体贴图 (Cubemap)</em></p>
<p>可以通过多种方式之一创建立方体贴图 (Cubemap)：</p>
<ol>
<li>使用 (Assets)-&gt;创建 (Create)-&gt;立方体贴图 (Cubemap),设置其属性，然后将六个<a target="_blank" rel="noopener" href="https://www.wenjiangs.com/doc/8cmt2UC9">纹理(Texture)</a> 资源拖动到对应立方体贴图 (Cubemap)“面”上。请注意，纹理在更改时必须重新应用，因为纹理会烘焙为立方体贴图资源 (Cubemap Asset)，无法链接到纹理。</li>
<li>使用<a target="_blank" rel="noopener" href="https://www.wenjiangs.com/doc/8cmt2UC9">纹理(Texture)</a> 导入设置从导入的单个纹理资源创建立方体贴图 (Cubemap)。</li>
<li>从脚本将场景渲染为立方体贴图 (Cubemap)。 Camera.RenderToCubemap 页面中的代码示例包含用于从编辑器直接渲染立方体贴图 (Cubemap) 的脚本。</li>
</ol>
<h2 id="属性"><a href="#属性" class="headerlink" title="属性"></a>属性</h2><div class="table-container">
<table>
<thead>
<tr>
<th style="text-align:left">属性：</th>
<th style="text-align:left">功能：</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">右 (+X) (Right (+X))</td>
<td style="text-align:left">立方体贴图 (Cubemap) 面右全局面的纹理。</td>
</tr>
<tr>
<td style="text-align:left">左 (-X) (Left (-X))</td>
<td style="text-align:left">立方体贴图 (Cubemap) 面上全局面的纹理。</td>
</tr>
<tr>
<td style="text-align:left">上 (+Y) (Top (+Y))</td>
<td style="text-align:left">立方体贴图 (Cubemap) 面上全局面的纹理。</td>
</tr>
<tr>
<td style="text-align:left">下 (-Y) (Bottom (-Y))</td>
<td style="text-align:left">立方体贴图 (Cubemap) 面下全局面的纹理。</td>
</tr>
<tr>
<td style="text-align:left">前 (+Z) (Front (+Z))</td>
<td style="text-align:left">立方体贴图 (Cubemap) 面前全局面的纹理。</td>
</tr>
<tr>
<td style="text-align:left">后 (-Z) (Front (-Z))</td>
<td style="text-align:left">立方体贴图 (Cubemap) 面后全局面的纹理。</td>
</tr>
<tr>
<td style="text-align:left">面大小 (Face Size)</td>
<td style="text-align:left">每个单独立方体贴图 (Cubemap) 面的宽度和高度（以像素为单位）。纹理会在内部缩放以适应此大小，无需手动缩放资源。</td>
</tr>
<tr>
<td style="text-align:left">多层贴图 (Mipmap)</td>
<td style="text-align:left">启用可创建多层贴图。</td>
</tr>
<tr>
<td style="text-align:left">格式 (Format)</td>
<td style="text-align:left">创建的立方体贴图 (Cubemap) 的格式。</td>
</tr>
</tbody>
</table>
</div>
<p><img src="image-20220515211458145.png" alt="image-20220515211458145"></p>
<p>将其绑定到这个位置 并设计好参数</p>
<p>public class MapCreate : MonoBehaviour<br>{<br>    /// <summary>
    /// 关卡数
    /// </summary><br>    public int Level;<br>    public int[,,] map = new int[1, 10, 10]<br>        {<br>            {<br>                {1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },<br>                {1, 1, 1,-1,-1,-1,-1,-1,-1, 1 },<br>                {1,-1,-1,-1, 1,-1, 1, 1, 1, 1 },<br>                {1, 1,-1,-1,-1,-1,-1,-1,-1, 1 },<br>                {1, 1, 1, 1, 1,-1,-1,-1,-1, 1 },<br>                {1,-1,-1,-1,-1,-1,-1,-1,-1, 1 },<br>                {1, 1, 1,1,1,1,1,1,1,1 },<br>                {1, 1, 1,1,1,1,1,1,1,1 },<br>                {1, 1, 1,1,1,1,1,1,1,1 },<br>                {1, 1, 1,1,1,1,1,1,1,1 }<br>            }<br>        };<br>    public GameObject road1;<br>    public GameObject obstacle1;<br>    public int width, high;<br>    // Start is called before the first frame update<br>    void Start()<br>    {<br>        for(int i=0;i&lt;width;i++)<br>            for(int j=0;j&lt;high;j++)<br>            {<br>                if (map[0, i, j] == 1)<br>                    Instantiate(obstacle1, new Vector3(10 <em> i, 5,10  </em> j), new Quaternion(0, 0, 0, 0));<br>                else if (map[0, i, j] == -1)<br>                    Instantiate(road1, new Vector3(10  <em> i, 5, 10 </em> j), new Quaternion(0, 0, 0, 0));<br>            }<br>    }</p>
<pre><code>// Update is called once per frame
void Update()
&#123;

&#125;
</code></pre><p>}</p>
<p>或则手工放置地图方块</p>
<p>cube添加贴图方法</p>
<p><strong>blender 创建具有贴图材质的模型，导入到Unity中</strong></p>
<p>环境：<br>win10<br>blender 2.79<br>unity 5.8.2</p>
<p>一、新建一个cube</p>
<p><img src="image-20220522231458239.png" alt="image-20220522231458239"></p>
<p>1.打开一个UV图像编辑器窗口</p>
<p><img src="image-20220523010831259.png" alt="image-20220523010831259"></p>
<p>2.在三维视图按Tab进入编辑模式</p>
<p>3.按U键调出菜单，选第二项点确定</p>
<p><img src="image-20220523011930468.png" alt="image-20220523011930468"></p>
<p>三、加贴图<br>1.打开一张图（我随便找了一张）</p>
<p>地图编辑器感谢<a target="_blank" rel="noopener" href="https://space.bilibili.com/2059519">梦符佳月</a></p>
<p><strong>使用方法：</strong></p>
<p>1.在Excel中输入地形编号，绘制关卡平面图</p>
<p><img src="43b38a851ba7dd93e9c84a8bdb0f4bb186f4cf0a.jpg@942w_569h_progressive.webp" alt="img"></p>
<p>例如上图，敌人将从红色方格（0）进入战场，走过黄色方格（2）（3），最终进入蓝色方格（1）。</p>
<p>玩家可以在（2）（4）上布置干员建立防守阵线。</p>
<p>如果敌人被移动至（6）中，则原地去世。</p>
<p>（7）是地图边沿，大型的配景模型将放置于此。</p>
<p>据此，相信游玩过《明日方舟》的网友可以在脑海中构建出关卡的大致样式。</p>
<p>之后，在保持excel开启的状态下，打开rhino，打开文件“地图样板”</p>
<p><img src="b1992e00cd18c063c49fb763a3de709d38a59e69.jpg@942w_546h_progressive.webp" alt="img">这个文件里没有几何物件，但是预先分好了图层，区别了材质，设立了几个视角</p>
<p>打开Grasshopper，打开文件“地图制作器”</p>
<p><img src="776f3da73668fa8d6ed0274a921b38d97a3487e2.jpg@770w_1203h_progressive.webp" alt="img">文末有源文件下载，截图就随便一点了</p>
<p>点击位于左上角的“读取表格”按钮，并调整读取的工作表序号和行列范围</p>
<p><img src="4b95d5881b702068519140124277043ac05128ac.jpg@942w_510h_progressive.webp" alt="img"></p>
<p>之后启用标有“预览”的电池Custom Preview，就可以在rhino中看到关卡预览</p>
<p>浅黄色部分是可以放置干员的地形，灰色的则相反。</p>
<p>如果对关卡设计不满意，可以在excel中修改</p>
<p><img src="541f40abd2916243a2209e2436c726cfa7aec1c6.jpg@942w_467h_progressive.webp" alt="img">使用条件格式，使单元格背景颜色随数值变化，便于查看。数值是控制地形的关键，颜色不是。</p>
<p>修改完成后，回到grasshopper，点击“读取表格”即可看到修改成果</p>
<p><img src="57613e935ddffe892af08546ba4dfadf08b5b06a.jpg@942w_531h_progressive.webp" alt="img"></p>
<p>之后，禁用标有“预览”的电池Custom Preview，点击“生成模型”按钮，即可完成建模。</p>
<p><img src="3852e58f4d0fe6944369b0194e48929803881b62.jpg@942w_546h_progressive.webp" alt="img"></p>
<p>之后，切换为渲染模式，获得更佳观看体验</p>
<p><img src="8c2b359a6d0c3f9bda5c0af169caf9ee059fda56.jpg@942w_546h_progressive.webp" alt="img"></p>
<p><strong>说明：</strong></p>
<p>1.流程概况</p>
<p>所有几何物件均为网格，整个过程大量数学运算，少量曲线布尔，基本不含物理运算，因此生成速度很快。生成上图所示模型，用时不到1秒。</p>
<p>2.数据流向</p>
<p>“预览”部分的参数、数据和最终生成的模型参数、数据不互通。</p>
<p>在点击“生成模型”之前，下半部分所有电池都不会收到数据，请放心调整。</p>
<p>3.“配景”的分类方式</p>
<p>（7）被我分成了三部分：南，北，和两侧，分离方法是这样的：</p>
<p><img src="eb6fd6fe479d0369cd41051ef763f5251f241fef.jpg@942w_546h_progressive.webp" alt="img"></p>
<p>若要调整分离方式，需要调整此滑杆：</p>
<p><img src="838cdb52133477b458b719b5176a1db82cac17a2.jpg@942w_512h_progressive.webp" alt="img"></p>
<p>4.特殊配景的出现规则</p>
<p>两侧建筑、白色铁架 是特殊的配景类物件，我设定了以下规则以让他们并不能总是出现，以保持配景的丰富度。</p>
<p>两侧建筑：对两侧的曲线进行布尔并集后，任意一边的长度都大于网格尺寸。</p>
<p>如下图所示，白色边框所示位置将出现建筑</p>
<p><img src="6fbfd68ca128466f8ff767a47cc21e2e67d4ecda.jpg@942w_543h_progressive.webp" alt="img"></p>
<p><img src="2c9882c0941ae016cc49b1e0d415f6301a8a8792.jpg@942w_534h_progressive.webp" alt="img"></p>
<p>下图所示情况则不会出现建筑，因为白色边框的区域，在布尔并集后，各曲线都至少有一条边是不大于网格尺寸的。</p>
<p><img src="4b0a8665877a6db35906d5c3490807a4e608dc55.jpg@942w_647h_progressive.webp" alt="img"></p>
<p><img src="bfeaed96e57cc3448e4afb41fd87c2873a35267f.jpg@942w_534h_progressive.webp" alt="img"></p>
<p>白色铁架：仅出现在南侧配景中，当且仅当有4个7相连时才会出现。</p>
<p><img src="afe4c8be6b7dd1de73b048a42f384b5e2cee0f68.jpg@942w_642h_progressive.webp" alt="img"></p>
<p><img src="bec33ec8b86a57c4b18e0bb612ba21707693b349.jpg@942w_347h_progressive.webp" alt="img"></p>
<p>其余所有配景或者同种地形的不同表现方式均为随机生成，可以通过调节参数进行控制。</p>
<p>5.所有的 调整是有意义的 参数滑杆我都放在cluster外面，并标上了注释。</p>
<p><img src="62b3228f3b568974af150ce9e1883c058faeffc1.jpg@942w_546h_progressive.webp" alt="img"></p>
<p>其中，标注有“1”“2”的滑杆，属于以下情况中的一种：</p>
<p><img src="2be2000841d92611d502967481f262305b356f1c.jpg@942w_807h_progressive.webp" alt="img"></p>
<p>功能相似的两个参数</p>
<p>有运算先后顺序的两个参数</p>
<p>一个区间的两个最值</p>
<p>6.必需的运行环境</p>
<p>rhino6.0</p>
<p>grasshopper1.0</p>
<p>插件 lunchbox（读取excel、自动bake、随机分组）</p>
<p>插件human（应用立方体贴图轴）</p>
<p>插件kangaroo2（删除重复直线、网格清理）</p>
<p>插件meshedit （炸开网格）</p>
<p>插件meshtool（网格管）</p>
<p><strong>文件下载：</strong></p>
<p>链接：<a target="_blank" rel="noopener" href="https://pan.baidu.com/s/1_2JzYxjxXiSdfOTIJytfHg">https://pan.baidu.com/s/1_2JzYxjxXiSdfOTIJytfHg</a></p>
<p>提取码：7nmp</p>
<p><strong>一些效果图</strong></p>
<p><img src="e9aa69df640d1dc5fb3ff99bc2dbbe37aa33a86e.png@942w_531h_progressive.webp" alt="img"></p>
<p><img src="5222ae2b097e5c795c12dfed90804e4cb39a0ef4.png@942w_531h_progressive.webp" alt="img"></p>
<p><img src="ddddc7107acbf24518168c3054bf6234c1a2321d.png@942w_531h_progressive.webp" alt="img"></p>
<p><img src="d3e6e5a570df11ca1c22cf607532ec18a163c70e.png@942w_531h_progressive.webp" alt="img"></p>
<p>设置敌人在起点创建（生命值）</p>
<p>设置敌人按轨迹移动</p>
<p>设置敌人终点消失</p>
<p>添加角色子弹与敌人的碰撞检测</p>
<p><img src="image-20220603230939765.png" alt="image-20220603230939765"></p>
<p><img src="image-20220603230957171.png" alt="image-20220603230957171"></p>
<p><strong>4.World: 多个地图块组成的世界，就是“我的世界”啦。</strong></p>
<p>我们可以看到这4个层次，其实有点类似俄罗斯套娃对吧，一层包含一层。</p>
<p>我们要生成World，那么就是要在这些层次中，一层一层的去处理生成的逻辑， 在World里动态加载Chunk, 在Chunk里生成Block, 在Block里生成Face。</p>
<p>1.首先我们先实现Chunk的生成，内部会包含 Block的生成，这里会用到simplex noise（一种Perlin噪声的改进）</p>
<p>有关噪声的知识，如果读者没有接触过，可以自行网上找找相关资料看看</p>
<p>这里推荐一篇（小姐姐写的比较细致）：<a href="https://link.zhihu.com/?target=http%3A//blog.csdn.net/candycat1992/article/details/50346469">【图形学】谈谈噪声 - candycat - CSDN博客</a></p>
<p>在这个部分我们会写一个类Chunk.cs, (大约200行代码)</p>
<p>2.接下来我们要通过玩家的位置信息来动态加载Chunk</p>
<p>这个部分我们会写一个类Player.cs (大约100行代码)</p>
<h2 id="Chunk生成"><a href="#Chunk生成" class="headerlink" title="Chunk生成"></a><strong>Chunk生成</strong></h2><p>首先新建一个Unity工程后，导入一些资源，资源包在这里下载：<a href="https://link.zhihu.com/?target=http%3A//pan.baidu.com/s/1hszPgwc">http://pan.baidu.com/s/1hszPgwc</a></p>
<p>接下来我们在场景中创建一个Cube</p>
<p>打开刚才新建的Chunk.cs，我们来先声明好Chunk类里需要用到的成员变量</p>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">Chunk</span> : <span class="title">MonoBehaviour</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="comment">//Block的类型</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">enum</span> BlockType</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">//空</span></span><br><span class="line">        None = <span class="number">0</span>,</span><br><span class="line">        <span class="comment">//泥土</span></span><br><span class="line">        Dirt = <span class="number">1</span>,</span><br><span class="line">        <span class="comment">//草地</span></span><br><span class="line">        Grass = <span class="number">3</span>,</span><br><span class="line">        <span class="comment">//碎石</span></span><br><span class="line">        Gravel = <span class="number">4</span>,</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//存储着世界中所有的Chunk</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="title">List</span>&lt;<span class="title">Chunk</span>&gt; chunks</span> = <span class="keyword">new</span> List&lt;Chunk&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//每个Chunk的长宽Size</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">int</span> width = <span class="number">30</span>;</span><br><span class="line">    <span class="comment">//每个Chunk的高度</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">int</span> height = <span class="number">30</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//随机种子</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">int</span> seed;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//最小生成高度</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">float</span> baseHeight = <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//噪音频率（噪音采样时会用到）</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">float</span> frequency = <span class="number">0.025f</span>;</span><br><span class="line">    <span class="comment">//噪音振幅（噪音采样时会用到）</span></span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">float</span> amplitude = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//存储着此Chunk内的所有Block信息</span></span><br><span class="line">    BlockType[,,] map;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//Chunk的网格</span></span><br><span class="line">    Mesh chunkMesh;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//噪音采样时会用到的偏移</span></span><br><span class="line">    Vector3 offset0;</span><br><span class="line">    Vector3 offset1;</span><br><span class="line">    Vector3 offset2;</span><br><span class="line"></span><br><span class="line">    MeshRenderer meshRenderer;</span><br><span class="line">    MeshCollider meshCollider;</span><br><span class="line">    MeshFilter meshFilter;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>接下来，我们往这个类中加一些初始化的函数 如下：</p>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">Start</span> (<span class="params"></span>)</span></span><br><span class="line">   &#123;</span><br><span class="line">       <span class="comment">//初始化时将自己加入chunks列表</span></span><br><span class="line">       chunks.Add(<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">//获取自身相关组件引用</span></span><br><span class="line">meshRenderer = GetComponent&lt;MeshRenderer&gt;();</span><br><span class="line">meshCollider = GetComponent&lt;MeshCollider&gt;();</span><br><span class="line">meshFilter = GetComponent&lt;MeshFilter&gt;();</span><br><span class="line"></span><br><span class="line">       <span class="comment">//初始化地图</span></span><br><span class="line">       InitMap();</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="function"><span class="keyword">void</span> <span class="title">InitMap</span>(<span class="params"></span>)</span></span><br><span class="line">   &#123;</span><br><span class="line">       <span class="comment">//初始化随机种子</span></span><br><span class="line">       Random.InitState(seed);</span><br><span class="line">       offset0 = <span class="keyword">new</span> Vector3(Random.<span class="keyword">value</span> * <span class="number">1000</span>, Random.<span class="keyword">value</span> * <span class="number">1000</span>, Random.<span class="keyword">value</span> * <span class="number">1000</span>);</span><br><span class="line">       offset1 = <span class="keyword">new</span> Vector3(Random.<span class="keyword">value</span> * <span class="number">1000</span>, Random.<span class="keyword">value</span> * <span class="number">1000</span>, Random.<span class="keyword">value</span> * <span class="number">1000</span>);</span><br><span class="line">       offset2 = <span class="keyword">new</span> Vector3(Random.<span class="keyword">value</span> * <span class="number">1000</span>, Random.<span class="keyword">value</span> * <span class="number">1000</span>, Random.<span class="keyword">value</span> * <span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">       <span class="comment">//初始化Map</span></span><br><span class="line">       map = <span class="keyword">new</span> BlockType[width, height, width];</span><br><span class="line"></span><br><span class="line">       <span class="comment">//遍历map，生成其中每个Block的信息</span></span><br><span class="line">       <span class="keyword">for</span> (<span class="built_in">int</span> x = <span class="number">0</span>; x &lt; width; x++)</span><br><span class="line">       &#123;</span><br><span class="line">           <span class="keyword">for</span> (<span class="built_in">int</span> y = <span class="number">0</span>; y &lt; height; y++)</span><br><span class="line">           &#123;</span><br><span class="line">               <span class="keyword">for</span> (<span class="built_in">int</span> z = <span class="number">0</span>; z &lt; width; z++)</span><br><span class="line">               &#123;</span><br><span class="line">                   map[x, y, z] = GenerateBlockType(<span class="keyword">new</span> Vector3(x, y, z) + transform.position);</span><br><span class="line">               &#125;</span><br><span class="line">           &#125;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       <span class="comment">//根据生成的信息，Build出Chunk的网格</span></span><br><span class="line">       BuildChunk();</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>在上面这段代码中，我们需要注意两个点</p>
<p>1.这里的map存的是Chunk内每一个Block的信息</p>
<p>2.GenerateBlockType函数和BuildChunk函数，我们还没有实现</p>
<p>3.我们在Start函数被调用时，便将这个Chunk生成好了</p>
<p>在第二点中说的两个函数，便是我们接下来生成Chunk的两个核心步骤</p>
<p><strong>1.生成map信息（每个Block的类型，以及地形的高度信息）</strong></p>
<p><strong>2.构建Chunk用来显示的网格</strong></p>
<p>那么我们接下来分别看看如何实现这两步</p>
<p><strong>1.GenerateBlockType</strong></p>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="built_in">int</span> <span class="title">GenerateHeight</span>(<span class="params">Vector3 wPos</span>)</span></span><br><span class="line">   &#123;</span><br><span class="line"></span><br><span class="line">       <span class="comment">//让随机种子，振幅，频率，应用于我们的噪音采样结果</span></span><br><span class="line">       <span class="built_in">float</span> x0 = (wPos.x + offset0.x) * frequency;</span><br><span class="line">       <span class="built_in">float</span> y0 = (wPos.y + offset0.y) * frequency;</span><br><span class="line">       <span class="built_in">float</span> z0 = (wPos.z + offset0.z) * frequency;</span><br><span class="line"></span><br><span class="line">       <span class="built_in">float</span> x1 = (wPos.x + offset1.x) * frequency * <span class="number">2</span>;</span><br><span class="line">       <span class="built_in">float</span> y1 = (wPos.y + offset1.y) * frequency * <span class="number">2</span>;</span><br><span class="line">       <span class="built_in">float</span> z1 = (wPos.z + offset1.z) * frequency * <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line">       <span class="built_in">float</span> x2 = (wPos.x + offset2.x) * frequency / <span class="number">4</span>;</span><br><span class="line">       <span class="built_in">float</span> y2 = (wPos.y + offset2.y) * frequency / <span class="number">4</span>;</span><br><span class="line">       <span class="built_in">float</span> z2 = (wPos.z + offset2.z) * frequency / <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line">       <span class="built_in">float</span> noise0 = Noise.Generate(x0, y0, z0) * amplitude;</span><br><span class="line">       <span class="built_in">float</span> noise1 = Noise.Generate(x1, y1, z1) * amplitude / <span class="number">2</span>;</span><br><span class="line">       <span class="built_in">float</span> noise2 = Noise.Generate(x2, y2, z2) * amplitude / <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line">       <span class="comment">//在采样结果上，叠加上baseHeight，限制随机生成的高度下限</span></span><br><span class="line">       <span class="keyword">return</span> Mathf.FloorToInt(noise0 + noise1 + noise2 + baseHeight);</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="function">BlockType <span class="title">GenerateBlockType</span>(<span class="params">Vector3 wPos</span>)</span></span><br><span class="line">   &#123;</span><br><span class="line">       <span class="comment">//y坐标是否在Chunk内</span></span><br><span class="line">       <span class="keyword">if</span> (wPos.y &gt;= height)</span><br><span class="line">       &#123;</span><br><span class="line">           <span class="keyword">return</span> BlockType.None;</span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">       <span class="comment">//获取当前位置方块随机生成的高度值</span></span><br><span class="line">       <span class="built_in">float</span> genHeight = GenerateHeight(wPos);</span><br><span class="line"></span><br><span class="line">       <span class="comment">//当前方块位置高于随机生成的高度值时，当前方块类型为空</span></span><br><span class="line">       <span class="keyword">if</span> (wPos.y &gt; genHeight)</span><br><span class="line">       &#123;</span><br><span class="line">           <span class="keyword">return</span> BlockType.None;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">//当前方块位置等于随机生成的高度值时，当前方块类型为草地</span></span><br><span class="line">       <span class="keyword">else</span> <span class="keyword">if</span> (wPos.y == genHeight)</span><br><span class="line">       &#123;</span><br><span class="line">           <span class="keyword">return</span> BlockType.Grass;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">//当前方块位置小于随机生成的高度值 且 大于 genHeight - 5时，当前方块类型为泥土</span></span><br><span class="line">       <span class="keyword">else</span> <span class="keyword">if</span> (wPos.y &lt; genHeight &amp;&amp; wPos.y &gt; genHeight - <span class="number">5</span>)</span><br><span class="line">       &#123;</span><br><span class="line">           <span class="keyword">return</span> BlockType.Dirt;</span><br><span class="line">       &#125;</span><br><span class="line">       <span class="comment">//其他情况，当前方块类型为碎石</span></span><br><span class="line">       <span class="keyword">return</span> BlockType.Gravel;</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure>
<p>上面这两个函数实现了生成Block信息的过程</p>
<p>在上面这段代码中我们需要注意以下几点</p>
<p>1.GenerateHeight用于通过噪音来随机生成每个方块的高度，这种随机生成的方式相比其他方式更贴近我们想要的结果。普通的随机数得到的值都是离散的，均匀分布的结果，而通过simplex noise得到的结果，会是连续的。这样会获得更加真实，接近自然的效果。</p>
<p>\2. GenerateHeight中那些数字字面量，没有特殊意义，就是经验数值，为了生成结果能够产生更多变化而已。可以自己调整试试看。</p>
<p>3.GenerateHeight中对多个噪声的生成结果进行了叠加，这是为了混合出理想的结果，具体可以网上检索查阅噪声相关资料。</p>
<p>4.GenerateBlockType内，会利用在指定位置随机生成的高度，来决定当前Block的类型。最内层是岩石，中间混杂着泥土，地表则是草地。</p>
<p>在我们有了地形元素的类型信息后，我们就可以来构建Chunk的网格，以来显示我们的Chunk了。</p>
<p>接下来我们实现BuildChunk函数</p>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">BuildChunk</span>(<span class="params"></span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    chunkMesh = <span class="keyword">new</span> Mesh();</span><br><span class="line">    List&lt;Vector3&gt; verts = <span class="keyword">new</span> List&lt;Vector3&gt;();</span><br><span class="line">    List&lt;Vector2&gt; uvs = <span class="keyword">new</span> List&lt;Vector2&gt;();</span><br><span class="line">    List&lt;<span class="built_in">int</span>&gt; tris = <span class="keyword">new</span> List&lt;<span class="built_in">int</span>&gt;();</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//遍历chunk, 生成其中的每一个Block</span></span><br><span class="line">    <span class="keyword">for</span> (<span class="built_in">int</span> x = <span class="number">0</span>; x &lt; width; x++)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="built_in">int</span> y = <span class="number">0</span>; y &lt; height; y++)</span><br><span class="line">        &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="built_in">int</span> z = <span class="number">0</span>; z &lt; width; z++)</span><br><span class="line">            &#123;</span><br><span class="line">                BuildBlock(x, y, z, verts, uvs, tris);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">                </span><br><span class="line">    chunkMesh.vertices = verts.ToArray();</span><br><span class="line">    chunkMesh.uv = uvs.ToArray();</span><br><span class="line">    chunkMesh.triangles = tris.ToArray();</span><br><span class="line">    chunkMesh.RecalculateBounds();</span><br><span class="line">    chunkMesh.RecalculateNormals();</span><br><span class="line">    </span><br><span class="line">    meshFilter.mesh = chunkMesh;</span><br><span class="line">    meshCollider.sharedMesh = chunkMesh;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如上所示，BuildChunk函数内部遍历了Chunk内的每一个Block,为其生成网格数据，并在最后将生成的数据（顶点，UV, 索引）提交给了chunkMesh。</p>
<p>接下来我们实现BuildBlock函数</p>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">BuildBlock</span>(<span class="params"><span class="built_in">int</span> x, <span class="built_in">int</span> y, <span class="built_in">int</span> z, List&lt;Vector3&gt; verts, List&lt;Vector2&gt; uvs, List&lt;<span class="built_in">int</span>&gt; tris</span>)</span></span><br><span class="line">  &#123;</span><br><span class="line">      <span class="keyword">if</span> (map[x, y, z] == <span class="number">0</span>) <span class="keyword">return</span>;</span><br><span class="line"></span><br><span class="line">      BlockType typeid = map[x, y, z];</span><br><span class="line"></span><br><span class="line">      <span class="comment">//Left</span></span><br><span class="line">      <span class="keyword">if</span> (CheckNeedBuildFace(x - <span class="number">1</span>, y, z))</span><br><span class="line">          BuildFace(typeid, <span class="keyword">new</span> Vector3(x, y, z), Vector3.up, Vector3.forward, <span class="literal">false</span>, verts, uvs, tris);</span><br><span class="line">      <span class="comment">//Right</span></span><br><span class="line">      <span class="keyword">if</span> (CheckNeedBuildFace(x + <span class="number">1</span>, y, z))</span><br><span class="line">          BuildFace(typeid, <span class="keyword">new</span> Vector3(x + <span class="number">1</span>, y, z), Vector3.up, Vector3.forward, <span class="literal">true</span>, verts, uvs, tris);</span><br><span class="line"></span><br><span class="line">      <span class="comment">//Bottom</span></span><br><span class="line">      <span class="keyword">if</span> (CheckNeedBuildFace(x, y - <span class="number">1</span>, z))</span><br><span class="line">          BuildFace(typeid, <span class="keyword">new</span> Vector3(x, y, z), Vector3.forward, Vector3.right, <span class="literal">false</span>, verts, uvs, tris);</span><br><span class="line">      <span class="comment">//Top</span></span><br><span class="line">      <span class="keyword">if</span> (CheckNeedBuildFace(x, y + <span class="number">1</span>, z))</span><br><span class="line">          BuildFace(typeid, <span class="keyword">new</span> Vector3(x, y + <span class="number">1</span>, z), Vector3.forward, Vector3.right, <span class="literal">true</span>, verts, uvs, tris);</span><br><span class="line"></span><br><span class="line">      <span class="comment">//Back</span></span><br><span class="line">      <span class="keyword">if</span> (CheckNeedBuildFace(x, y, z - <span class="number">1</span>))</span><br><span class="line">          BuildFace(typeid, <span class="keyword">new</span> Vector3(x, y, z), Vector3.up, Vector3.right, <span class="literal">true</span>, verts, uvs, tris);</span><br><span class="line">      <span class="comment">//Front</span></span><br><span class="line">      <span class="keyword">if</span> (CheckNeedBuildFace(x, y, z + <span class="number">1</span>))</span><br><span class="line">          BuildFace(typeid, <span class="keyword">new</span> Vector3(x, y, z + <span class="number">1</span>), Vector3.up, Vector3.right, <span class="literal">false</span>, verts, uvs, tris);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="built_in">bool</span> <span class="title">CheckNeedBuildFace</span>(<span class="params"><span class="built_in">int</span> x, <span class="built_in">int</span> y, <span class="built_in">int</span> z</span>)</span></span><br><span class="line">  &#123;</span><br><span class="line">      <span class="keyword">if</span> (y &lt; <span class="number">0</span>) <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">      <span class="keyword">var</span> type = GetBlockType(x, y, z);</span><br><span class="line">      <span class="keyword">switch</span> (type)</span><br><span class="line">      &#123;</span><br><span class="line">          <span class="keyword">case</span> BlockType.None:</span><br><span class="line">              <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">          <span class="literal">default</span>:</span><br><span class="line">              <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">      &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> BlockType <span class="title">GetBlockType</span>(<span class="params"><span class="built_in">int</span> x, <span class="built_in">int</span> y, <span class="built_in">int</span> z</span>)</span></span><br><span class="line">  &#123;</span><br><span class="line">      <span class="keyword">if</span> (y &lt; <span class="number">0</span> || y &gt; height - <span class="number">1</span>)</span><br><span class="line">      &#123;</span><br><span class="line">          <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">//当前位置是否在Chunk内</span></span><br><span class="line">      <span class="keyword">if</span> ((x &lt; <span class="number">0</span>) || (z &lt; <span class="number">0</span>) || (x &gt;= width) || (z &gt;= width))</span><br><span class="line">      &#123;</span><br><span class="line">          <span class="keyword">var</span> id = GenerateBlockType(<span class="keyword">new</span> Vector3(x, y, z) + transform.position);</span><br><span class="line">          <span class="keyword">return</span> id;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> map[x, y, z];</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>
<p>（做了面优化）</p>
<p>我们的角色在地形上时，只能看到最外部的一层面，其实看不到内部的方块，所以这些看不到的方块，就没有必要浪费计算资源了。也正是这个原因，我们不能直接用正方体去随机生成，而是要像现在这样，以Face为基本单位来生成。实现这个功能的函数，便是CheckNeedBuildFace。</p>
<p>接下来让我们完成Chunk部分的最后一步</p>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">BuildFace</span>(<span class="params">BlockType typeid, Vector3 corner, Vector3 up, Vector3 right, <span class="built_in">bool</span> reversed, List&lt;Vector3&gt; verts, List&lt;Vector2&gt; uvs, List&lt;<span class="built_in">int</span>&gt; tris</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">    <span class="built_in">int</span> index = verts.Count;</span><br><span class="line">    </span><br><span class="line">    verts.Add (corner);</span><br><span class="line">    verts.Add (corner + up);</span><br><span class="line">    verts.Add (corner + up + right);</span><br><span class="line">    verts.Add (corner + right);</span><br><span class="line">    </span><br><span class="line">    Vector2 uvWidth = <span class="keyword">new</span> Vector2(<span class="number">0.25f</span>, <span class="number">0.25f</span>);</span><br><span class="line">    Vector2 uvCorner = <span class="keyword">new</span> Vector2(<span class="number">0.00f</span>, <span class="number">0.75f</span>);</span><br><span class="line"></span><br><span class="line">    uvCorner.x += (<span class="built_in">float</span>)(typeid - <span class="number">1</span>) / <span class="number">4</span>;</span><br><span class="line">    uvs.Add(uvCorner);</span><br><span class="line">    uvs.Add(<span class="keyword">new</span> Vector2(uvCorner.x, uvCorner.y + uvWidth.y));</span><br><span class="line">    uvs.Add(<span class="keyword">new</span> Vector2(uvCorner.x + uvWidth.x, uvCorner.y + uvWidth.y));</span><br><span class="line">    uvs.Add(<span class="keyword">new</span> Vector2(uvCorner.x + uvWidth.x, uvCorner.y));</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (reversed)</span><br><span class="line">    &#123;</span><br><span class="line">        tris.Add(index + <span class="number">0</span>);</span><br><span class="line">        tris.Add(index + <span class="number">1</span>);</span><br><span class="line">        tris.Add(index + <span class="number">2</span>);</span><br><span class="line">        tris.Add(index + <span class="number">2</span>);</span><br><span class="line">        tris.Add(index + <span class="number">3</span>);</span><br><span class="line">        tris.Add(index + <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">else</span></span><br><span class="line">    &#123;</span><br><span class="line">        tris.Add(index + <span class="number">1</span>);</span><br><span class="line">        tris.Add(index + <span class="number">0</span>);</span><br><span class="line">        tris.Add(index + <span class="number">2</span>);</span><br><span class="line">        tris.Add(index + <span class="number">3</span>);</span><br><span class="line">        tris.Add(index + <span class="number">2</span>);</span><br><span class="line">        tris.Add(index + <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这一步我们构建了正方体其中一面的网格数据，顶点，UV, 索引。这一步实现完后， 如果我们将这个组件挂在我们最初创建的Cube上，并运行，我们即会得到随机生成的一个Chunk。如下图所示：</p>
<p><img src="v2-998ea4beb691e080fb40d892db88165d_720w.jpg" alt="img"></p>
<p><img src="file:///C:\Users\admin\AppData\Roaming\Tencent\Users\1399130811\QQ\WinTemp\RichOle\821K(9G_L@R3HT(LDAF9V70.png" alt="img"><img src="C:/Users/admin/Desktop/821K(9G_L@R3HT(LDAF9V70.png" alt="821K(9G_L@R3HT(LDAF9V70"><img src="C:/Users/admin/Desktop/821K(9G_L@R3HT(LDAF9V70.png" alt="821K(9G_L@R3HT(LDAF9V70"><img src="sdf.png" alt="sdf"></p>
<p>地图场景初步搭建成功</p>
<p>下一步 让敌人在起点生成然后沿着路走向终点即可</p>
<p>那么我们就设计成在起点坐标 每隔4s生成1个怪物（怪物总数待定） </p>
<p>下一步 让召唤出的敌人按我们给定的路线前进</p>
<p>1创建空物体，在空物体里创建多个路径目标点。自定义脚本：RoadPoints</p>
<p>public class CreateEnemies : MonoBehaviour<br>{<br>    public int enemiesCount;<br>    /// <summary>
    /// 敌人
    /// </summary><br>    public GameObject Enemy;<br>    private int time = 1;<br>    // Start is called before the first frame update<br>    void Start()<br>    {</p>
<pre><code>&#125;

// Update is called once per frame
void Update()
&#123;
    time++;
    //每隔120帧召唤一个敌人
    if(time&gt;120)
    &#123;
        time = 0;
        Instantiate(Enemy, this.transform.position, this.transform.rotation);
    &#125;
&#125;
</code></pre><p>}</p>
<p>2.给移动物体Player自定义脚本</p>
<h3 id="Cinemachine-导入即可"><a href="#Cinemachine-导入即可" class="headerlink" title="Cinemachine 导入即可"></a>Cinemachine 导入即可</h3><p> <img src="image-20220604125533161.png" alt="image-20220604125533161"></p>
<p>二、添加移动轨道</p>
<p>Cinemachine中的CinemachineSmoothPath可以用来设计固定路线移动方案API参考<br>TrackAsset：<a target="_blank" rel="noopener" href="https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackAsset.html">https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackAsset.html</a><br>TrackBindingTypeAttribute：<a target="_blank" rel="noopener" href="https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackBindingTypeAttribute.html">https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackBindingTypeAttribute.html</a><br>TrackClipTypeAttribute：<br><a target="_blank" rel="noopener" href="https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackClipTypeAttribute.html">https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackClipTypeAttribute.html</a><br>TrackColorAttribute：<a target="_blank" rel="noopener" href="https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackColorAttribute.html">https://docs.unity3d.com/2018.3/Documentation/ScriptReference/Timeline.TrackColorAttribute.html</a><br>————————————————<br>版权声明：本文为CSDN博主「至肝主义圈毛君」的原创文章，遵循CC 4.0 BY-SA版权协议，转载请附上原文出处链接及本声明。<br>原文链接：<a target="_blank" rel="noopener" href="https://blog.csdn.net/Ha1f_Awake/article/details/101754700">https://blog.csdn.net/Ha1f_Awake/article/details/101754700</a></p>
<p><img src="image-20220604133218784.png" alt="image-20220604133218784"></p>
<p><img src="image-20220604133606275.png" alt="image-20220604133606275"></p>
<p>三、简单的移动逻辑（cube沿设计的路线移动）</p>
<p>public class EnemyMove : MonoBehaviour<br>{<br>    public GameObject join;<br>    public float m_Speed = 10;<br>    public CinemachineSmoothPath m_Path;</p>
<pre><code>private float m_Position = 0;
public PositionUnits m_type = PositionUnits.Distance;
public UpdateMethod m_method = UpdateMethod.SmartUpdate;

public Waypoint[] point;
void Start()
&#123;
    point = m_Path.m_Waypoints;
&#125;
void FixedUpdate()
&#123;
    if (m_method == UpdateMethod.FixedUpdate)
        SetCartPosition(m_Position + m_Speed * Time.deltaTime);


&#125;
void Update()
&#123;
    float speed = Application.isPlaying ? m_Speed : 0;
    if (m_method == UpdateMethod.SmartUpdate)
        SetCartPosition(m_Position + speed * Time.deltaTime);
&#125;
void LateUpdate()
&#123;
    if (!Application.isPlaying)
        SetCartPosition(m_Position);
    else if (m_method == UpdateMethod.LateUpdate)
        SetCartPosition(m_Position + m_Speed * Time.deltaTime);
&#125;
void SetCartPosition(float distanceAlongPath)
&#123;
    m_Position = m_Path.StandardizeUnit(distanceAlongPath， m_type);
    transform.position = m_Path.EvaluatePositionAtUnit(m_Position， m_type); transform.rotation = m_Path.EvaluateOrientationAtUnit(m_Position， m_type);
&#125;
</code></pre><p>}</p>
<p>将其绑定到预制体上（轨迹也要绑定）</p>
<p><img src="]HHLV8%SMAX${SOU{IDOBCC.png" alt="img"></p>
<p>下一步 设计qq人到达终点消失的方法</p>
<p>对象到达终点后 逐渐消失</p>
<p>为终点添加碰撞检测</p>
<p>public class Enemies : MonoBehaviour<br>{<br>    public GameObject join;<br>    // Start is called before the first frame update<br>    void Start()<br>    {</p>
<pre><code>&#125;

// Update is called once per frame
void Update()
&#123;

&#125;//碰撞开始  
void OnCollisionEnter(Collision collision)
&#123;
    if (collision.gameObject.name == &quot;Sphere&quot;)
    &#123;
        Destroy(collision.gameObject);
    &#125;
&#125;
</code></pre><p>}</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/03/08/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%BC%80%E5%8F%91%E6%B8%B8%E6%88%8F%E9%80%89%E6%8B%A9%E7%95%8C%E9%9D%A2%20-%20%E5%89%AF%E6%9C%AC/" data-id="cl403sxsd003zf8vu7okj583m" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-炉石传说/Untitled Folder/unity基础教程 如何创建对象" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/02/27/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/Untitled%20Folder/unity%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B%20%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1/" class="article-date">
  <time class="dt-published" datetime="2022-02-27T11:33:15.175Z" itemprop="datePublished">2022-02-27</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="unity对象管理-（一）"><a href="#unity对象管理-（一）" class="headerlink" title="unity对象管理 （一）"></a>unity对象管理 （一）</h1><h2 id="一、如何创建对象"><a href="#一、如何创建对象" class="headerlink" title="一、如何创建对象"></a>一、如何创建对象</h2><h3 id="1-背景"><a href="#1-背景" class="headerlink" title="1.背景"></a>1.背景</h3><ul>
<li>你可以在Unity中创建场景，并用对象实例填充它们。unity可以设计固定的关卡。但是当玩家退出然后再重新读取游戏时候，我们需要自己解决对象的创建问题。</li>
<li>在本教程中，我们会创建一个非常简单的游戏。它所做的一切就是在按下一个键时生成一个随机立方体。只要我们能够跟踪不同游戏会话（sessions）之间的立方体，就可以在以后的教程中增加游戏的复杂性。<h3 id="2-逻辑设置"><a href="#2-逻辑设置" class="headerlink" title="2.逻辑设置"></a>2.逻辑设置</h3></li>
<li><p>这里只使用game组件进行简单控制</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">public class NewBehaviourScript : MonoBehaviour</span><br><span class="line">&#123;</span><br><span class="line">    public Transform prefab;</span><br><span class="line">    // Start is called before the first frame update</span><br><span class="line">    void Start()</span><br><span class="line">    &#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // Update is called once per frame</span><br><span class="line">    void Update()</span><br><span class="line">    &#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>在场景中添加一个游戏对象，并将此组件附加到上面。然后再创建一个默认的立方体，把它转化成一个预置，并给游戏对象一个它的引用。</p>
<p><img src="v2-6cc7247d6b40f075385dda30c867141d_720w.jpg" alt="img"></p>
<p><img src="v2-f8a31f85a2a214ceac0ebad967b7125a_720w.jpg" alt="img"></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/02/27/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/Untitled%20Folder/unity%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B%20%E5%A6%82%E4%BD%95%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1/" data-id="cl403sxt5005rf8vu4rnj7hi4" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-炉石传说/unity的canves知识补充" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/02/27/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/unity%E7%9A%84canves%E7%9F%A5%E8%AF%86%E8%A1%A5%E5%85%85/" class="article-date">
  <time class="dt-published" datetime="2022-02-27T10:52:37.822Z" itemprop="datePublished">2022-02-27</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        
      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/02/27/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/unity%E7%9A%84canves%E7%9F%A5%E8%AF%86%E8%A1%A5%E5%85%85/" data-id="cl403sxsd003wf8vuat18810a" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-炉石传说/第一步开发游戏选择界面" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/02/27/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%BC%80%E5%8F%91%E6%B8%B8%E6%88%8F%E9%80%89%E6%8B%A9%E7%95%8C%E9%9D%A2/" class="article-date">
  <time class="dt-published" datetime="2022-02-27T10:10:52.868Z" itemprop="datePublished">2022-02-27</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="Unity中Canvas及三种渲染模式"><a href="#Unity中Canvas及三种渲染模式" class="headerlink" title="Unity中Canvas及三种渲染模式"></a>Unity中Canvas及三种渲染模式</h1><p><a target="_blank" rel="noopener" href="https://www.jianshu.com/u/dd75772068cc"><img src="3a74bed7-7c6d-405f-9bf0-8ec2fe7c3e34.jpg" alt="img"></a></p>
<p><a target="_blank" rel="noopener" href="https://www.jianshu.com/u/dd75772068cc">BucketHead</a>关注</p>
<p>12018.08.18 19:32:51字数 844阅读 13,969</p>
<h4 id="1-什么是Canvas"><a href="#1-什么是Canvas" class="headerlink" title="1. 什么是Canvas"></a><strong>1. 什么是Canvas</strong></h4><p>使用UGUI来进行UI开发，离不开Canvas组件，所有的 UI 元素，要么自己包含 Canvas 组件，要么是 Canvas 组件所在 GameObject 的子节点。</p>
<h4 id="2-如何创建-Canvas"><a href="#2-如何创建-Canvas" class="headerlink" title="2. 如何创建 Canvas"></a>2. 如何创建 Canvas</h4><p>你在 Hierarchy 视图创建任何一个 UI 元素（比如Image）都会自动生成一个 Canvas 作为它的父节点。你也可以可以直接创建一个 Canvas，然后添加其他 UI 元素作为其子节点。</p>
<h4 id="3-Canvas-组件的RenderMode-参数"><a href="#3-Canvas-组件的RenderMode-参数" class="headerlink" title="3. Canvas 组件的RenderMode 参数"></a>3. Canvas 组件的RenderMode 参数</h4><p>Canvas 组件的参数 RenderMode，有三个选项：Screen Space - Overlay、Screen Space - Camera、World Space。</p>
<p><img src="13097306-d3892db758a43812.png" alt="img"></p>
<p>Canvas 的 RenderMode 参数</p>
<h4 id="4-Screen-Space-Overlay-模式"><a href="#4-Screen-Space-Overlay-模式" class="headerlink" title="4. Screen Space - Overlay 模式"></a>4. Screen Space - Overlay 模式</h4><p>Canvas 覆盖屏幕，且永远覆盖在其它元素的上层，也就是说 UI 会遮挡场景中的其它元素。</p>
<p><img src="13097306-85d309ceb39688fc.png" alt="img"></p>
<p>Overlay 模式下 UI 总是渲染在3d元素的上面</p>
<p>当 RenderMode 为 Screen Space - Overlay时，Canvas的其它参数包括：</p>
<blockquote>
<p>Pixel Perfect：UI元素精确到像素对齐，边缘更清晰，但是在UI调整和适配时会有更大的计算量（个人理解）</p>
<p>Sort Order：Canvas 的深度。多个 存在多个Canvas时，Sort Order 值更大的Canvas会遮盖住 Sort Order 值小的 Canvas</p>
<p>注：多个 Canvas 深度取值相等时，Hierarchy 视图中后面的 Canvas 显示在下，这一点与 UI 元素（如Image的规则相反）</p>
</blockquote>
<h4 id="5-Screen-Space-Camera-模式"><a href="#5-Screen-Space-Camera-模式" class="headerlink" title="5. Screen Space - Camera 模式"></a>5. Screen Space - Camera 模式</h4><p>和 Overlay 模式相仿，Canvas覆盖整个屏幕空间画布也是填满整个屏幕空间。不同之处在于，Canvas 被放置于指定摄像机的前方。</p>
<p><img src="13097306-a21df121e7a8b8ca.png" alt="img"></p>
<p>Canvas 被放置在摄像机的前方</p>
<p>这种模式下面 UI 并不一定能渲染在 3d 元素之上</p>
<p><img src="13097306-2ceb84add258a833.png" alt="img"></p>
<p>Camera 模式下，3d 元素可能渲染在UI之上</p>
<p>且</p>
<blockquote>
<p>(1) 必须在摄像机的远近平面之间才会被渲染</p>
<p>(2) 即使摄像机是 Perspective 模式，Canvas 距离摄像机的远近依然不会影响其显示大小</p>
<p>(3) 其它3元素可以和 Canvas 产生遮挡关系，距离摄像机更近的元素会遮盖住 Canvas 上面的 UI</p>
<p>(4) 摄像机的缩放/平移/旋转，以及 fov 的变化，不会影响 Canvas 显示结果，Canvas 永远是放置在距离摄像机视口一定距离的地方，且与摄像机水平视线垂直</p>
</blockquote>
<p>Screen Space - Camera 的参数包括：</p>
<p><img src="13097306-a9cbda1a02e6d487.png" alt="img"></p>
<p>Screen Space - Camera 模式 Canvas 的参数</p>
<p>Pixel Perfect ：同 Overlay 模式含义</p>
<p>Render Camera ：指定的用来渲染 Canvas 的摄像机</p>
<p>Plane Distance：Canvas 平面距离摄像机的距离</p>
<p>Sorting Layer：指示 Canvas 的深度，可以手动添加。当存在多个模式为 Screen Space 的 Canvas 时，Sorting Layer 决定了显示的优先级。</p>
<p>Order in Layer：多个 Canvas 具有相同的 Sorting Layer 时，根据 Order in Layer 来确定显示优先级。</p>
<h4 id="5-World-Space-模式"><a href="#5-World-Space-模式" class="headerlink" title="5. World Space 模式"></a>5. World Space 模式</h4><p>此种模式下，Canvas 与场景中其它3D元素没有区别</p>
<p><img src="13097306-6f31845ec870f334.png" alt="img"></p>
<p>World space 模式的Canvas 本质上就是3d 元素</p>
<p>此时</p>
<blockquote>
<p>Canvas 可以调整 RectTransform 的数值</p>
<p>摄像机的平移旋转缩放及fov都会影响 Canvas 的显示</p>
<p>需要 EventCamera 来指定接受事件的摄像机</p>
</blockquote>
<h4 id="6-总结"><a href="#6-总结" class="headerlink" title="6. 总结"></a>6. 总结</h4><p>不同模式的 Canvas之间，Screen Space - Overlay 的 Canvas 永远显示在最前面，Screen Space - Camera 和 World 的显示关系决定于 World Canvas 距离摄像机的位置以及 Screen Space - Camera Canvas 的 Plane Distance</p>
<p>相同的 Screen Space - Overlay Canvas ：显示优先级由 Sort Order 确定</p>
<p>相同的 Screen Space - Camera：显示优先级由 Sorting Layer 和 Order in Layer 确定</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/02/27/%E7%82%89%E7%9F%B3%E4%BC%A0%E8%AF%B4/%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%BC%80%E5%8F%91%E6%B8%B8%E6%88%8F%E9%80%89%E6%8B%A9%E7%95%8C%E9%9D%A2/" data-id="cl403sxse0041f8vubj8shmt3" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  
    <article id="post-python/python编写小型数据库" class="h-entry article article-type-post" itemprop="blogPost" itemscope itemtype="https://schema.org/BlogPosting">
  <div class="article-meta">
    <a href="/notes-on-computer-expertise/2022/02/23/python/python%E7%BC%96%E5%86%99%E5%B0%8F%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93/" class="article-date">
  <time class="dt-published" datetime="2022-02-23T11:02:52.989Z" itemprop="datePublished">2022-02-23</time>
</a>
    
  </div>
  <div class="article-inner">
    
    
    <div class="e-content article-entry" itemprop="articleBody">
      
        <h1 id="python编写小型数据库"><a href="#python编写小型数据库" class="headerlink" title="python编写小型数据库"></a>python编写小型数据库</h1><h2 id="二、结构设计"><a href="#二、结构设计" class="headerlink" title="二、结构设计"></a>二、结构设计</h2><ul>
<li><ul>
<li>库模块</li>
<li>表模块</li>
<li>字段模块</li>
<li>引擎模块</li>
<li>条件模块</li>
<li>解析模块</li>
<li>交互模块</li>
<li>异常处理模块</li>
</ul>
</li>
<li>以这些模块为基础，并且它的整体是作为一个 Python三方库存在，所以按每一个模块一个包来分，结构如下<ul>
<li>syldb #这个库的名字,导入时语句为:import syldb<ul>
<li>_init__-py #模块主体,作为调度其他模块的入口，也就是引擎模块</li>
<li>_main_.py #直接调用模块时的入口，也就是当执行 python3 -m syldb时执行的文件</li>
<li>case #条件判断模块<ul>
<li>_init_-py</li>
</ul>
</li>
<li>core#核心模块-<ul>
<li>_init_-py #核心模块主体</li>
<li>database.py#数据库模块</li>
<li>field.py #数据库字段模块</li>
<li>table.py #数据表模块</li>
</ul>
</li>
<li>exceptions #异常处理模块<ul>
<li>_init__-py</li>
</ul>
</li>
<li>parser # SQL 语法解析模块<ul>
<li>_init__.Py<h2 id="三、项目创建"><a href="#三、项目创建" class="headerlink" title="三、项目创建"></a>三、项目创建</h2></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>下面是创建项目的脚本，复制粘贴到/home/ shiyanlou/Code目录下的 gen.py 文件中运行就可以创建好上面定义出来的目录结构<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># !/ usr/bin/env python3#encoding: utf-8</span></span><br><span class="line"><span class="keyword">import</span> os</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="comment">#在当前目录下创建</span></span><br><span class="line">root_path = os.getcwd()</span><br><span class="line"><span class="comment">#目录列表</span></span><br><span class="line"><span class="comment">#子文件</span></span><br><span class="line">children = <span class="string">&#x27;&#123;&quot;name&quot;:&quot;%s.py&quot;,&quot;children&quot;:[],&quot;type&quot;: &quot;file&quot;&#125;&#x27;</span></span><br><span class="line"><span class="comment">#目录结构</span></span><br><span class="line">dir_map=[&#123;</span><br><span class="line">    <span class="comment"># name为模块的名字:建议用 syldb命名，方便后续的实验与课程同步</span></span><br><span class="line">    <span class="string">&quot;name&quot;</span> : <span class="string">&quot;syldb&quot;</span>,</span><br><span class="line">    <span class="string">&quot;type&quot;</span> : <span class="string">&quot;dir&quot;</span>,</span><br><span class="line">    <span class="string">&quot;children&quot;</span>:[</span><br><span class="line">        json.loads(children % <span class="string">&#x27;__init__&#x27;</span>),</span><br><span class="line">        json.loads(children % <span class="string">&#x27;__main__&#x27;</span>),</span><br><span class="line">        &#123;</span><br><span class="line">        <span class="string">&quot;name&quot;</span> : <span class="string">&quot;case&quot;</span>,</span><br><span class="line">        <span class="string">&quot;type&quot;</span> : <span class="string">&quot;dir&quot;</span>,</span><br><span class="line">        <span class="string">&quot;children&quot;</span> : [json.loads(children % <span class="string">&#x27;__init__&#x27;</span>)]</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">        <span class="string">&quot;name&quot;</span> : <span class="string">&quot;parse&quot;</span>,</span><br><span class="line">        <span class="string">&quot;type&quot;</span> :<span class="string">&quot;dir&quot;</span>,</span><br><span class="line">        <span class="string">&quot;children&quot;</span>: [json.loads(children % <span class="string">&#x27;__init__&#x27;</span>)]</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">        <span class="string">&quot;name&quot;</span> : <span class="string">&quot;exceptions&quot;</span>,</span><br><span class="line">        <span class="string">&quot;type&quot;</span> : <span class="string">&quot;dir&quot;</span>,</span><br><span class="line">        <span class="string">&quot;children&quot;</span>: [json.loads(children % <span class="string">&quot;__init__&quot;</span>)]</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">        <span class="string">&quot;name&quot;</span> : <span class="string">&quot;core&quot;</span>,</span><br><span class="line">        <span class="string">&quot;type&quot;</span> : <span class="string">&quot;dir&quot;</span>,</span><br><span class="line">        <span class="string">&quot;children&quot;</span>: [</span><br><span class="line">            json.loads(children % <span class="string">&quot;__init__&quot;</span>),</span><br><span class="line">            json.loads(children % <span class="string">&quot;database&quot;</span>),</span><br><span class="line">            json.loads(children % <span class="string">&quot;table&quot;</span>),</span><br><span class="line">            json.loads(children % <span class="string">&quot;field&quot;</span>)]</span><br><span class="line">        &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;]</span><br><span class="line"><span class="comment">#创建文件夹或者文件</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">create</span>(<span class="params">path,kind</span>):</span></span><br><span class="line">    <span class="keyword">if</span> kind == <span class="string">&quot;dir&quot;</span>:</span><br><span class="line">        os.mkdir(path)</span><br><span class="line">    <span class="keyword">else</span>:</span><br><span class="line">        <span class="built_in">open</span>(path, <span class="string">&quot;w&quot;</span>).close()</span><br><span class="line"><span class="comment">#递归创建目录</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">gen_project</span>(<span class="params">parent_path,map_obj</span>):</span></span><br><span class="line">    <span class="keyword">for</span> line <span class="keyword">in</span> map_obj:</span><br><span class="line">        path = os.path.join(parent_path,line[<span class="string">&quot;name&quot;</span>])</span><br><span class="line">        create(path,line[<span class="string">&#x27;type&#x27;</span>])</span><br><span class="line">        <span class="keyword">if</span> line[<span class="string">&#x27;children&#x27;</span>]:</span><br><span class="line">            gen_project(path,line[<span class="string">&quot;children&quot;</span>])</span><br><span class="line">    <span class="comment">#脚本入口</span></span><br><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">main</span>():</span></span><br><span class="line">    gen_project(root_path, dir_map)</span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span> :</span><br><span class="line">    main()</span><br></pre></td></tr></table></figure>
<h1 id="数据字段模块的实现"><a href="#数据字段模块的实现" class="headerlink" title="数据字段模块的实现"></a>数据字段模块的实现</h1><h2 id="一、实验说明"><a href="#一、实验说明" class="headerlink" title="一、实验说明"></a>一、实验说明</h2><h3 id="1-1内容"><a href="#1-1内容" class="headerlink" title="1.1内容"></a>1.1内容</h3></li>
<li>本节开始进行数据库核心模块之一的数据库字段模块的实现。<h3 id="1-2涉及知识点"><a href="#1-2涉及知识点" class="headerlink" title="1.2涉及知识点"></a>1.2涉及知识点</h3></li>
<li>序列化</li>
<li>反序列化</li>
<li>Json<h3 id="1-3实验环境"><a href="#1-3实验环境" class="headerlink" title="1.3实验环境"></a>1.3实验环境</h3></li>
<li>Python3</li>
<li>xfce终端<h2 id="二、模块功能分析"><a href="#二、模块功能分析" class="headerlink" title="二、模块功能分析"></a>二、模块功能分析</h2></li>
<li>这个模块是数据库核心模块之一，所以定义在核心模块目录 core目录下的field.py 中，由于它是数据结构的最底层，所以选择从它开始设计实现。</li>
<li>它需要实现的有数据类型定义，数据类型约束，而且为了数据库的保存和加载，这里引入了序列化和反序列化的概念，然后根据我们之前的数据结构模型可以看到它是一个键值对方式存在，值应该是一个List列表，并且作为实际存放数据的结构体，它还需要支持数据操作，也就是基础的增、删、改、查操作，总结之后它具备的必备功能大致如下<ul>
<li>一个存放值的List列表</li>
<li>可定义数据类型</li>
<li>可定义数据约束</li>
<li>支持序列化和反序列化</li>
<li>支持增、删、改、查基础操作<h2 id="三、序列化和反序列化"><a href="#三、序列化和反序列化" class="headerlink" title="三、序列化和反序列化"></a>三、序列化和反序列化</h2><h3 id="3-1概念"><a href="#3-1概念" class="headerlink" title="3.1概念"></a>3.1概念</h3></li>
</ul>
</li>
<li>序列化其实就是把一个对象的结果转换成一段具有一定格式的数据，使它可以从内存中取出来并保存下来，并且可以通过反序列化把这段数据重新还原成一个原先的对象，保持状态属性的一致。比如我们这里要实现的数据字段模块，它是一个Field对象，拥有的属性包括值，数据类型，数据约束和基础操作，那么序列化就是把这个对象当前拥有的这些属性值保存下来，然后下次使用的时候解析加载这些值还原成这个对象，拥有原先的值，数据类型，数据约束和基础操作<h3 id="3-2定义序列化和反序列化接口"><a href="#3-2定义序列化和反序列化接口" class="headerlink" title="3.2定义序列化和反序列化接口"></a>3.2定义序列化和反序列化接口</h3></li>
<li>因为我们要保存的是整个数据结构，所有核心模块都需要实现序列化和反序列化，所以可以预定义一个接口规范，定义在核心模块目录core下的<strong>init</strong>.py中，代码如下<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> json</span><br><span class="line"><span class="comment">#数据库核心模块序列化接口</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">serializedInterface</span>:</span></span><br><span class="line">    json = json <span class="comment">#内部定义一个json 对象,方便后续操作不需要import</span></span><br><span class="line">    <span class="comment">#反序列化方法</span></span><br><span class="line"><span class="meta">    @staticmethod</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">deserialized</span>(<span class="params">obj</span>):</span></span><br><span class="line">        <span class="keyword">raise</span> NotImplementedError<span class="comment">#抛出未实现异常</span></span><br><span class="line">    <span class="comment">#序列化方法</span></span><br><span class="line">    <span class="function"><span class="keyword">def</span> <span class="title">serialized</span>(<span class="params">self</span>) :</span></span><br><span class="line">        <span class="keyword">raise</span> NotImplementedError<span class="comment">#抛出未实现异常</span></span><br></pre></td></tr></table></figure>
<h2 id="四、定义数据类型"><a href="#四、定义数据类型" class="headerlink" title="四、定义数据类型"></a>四、定义数据类型</h2></li>
<li>对于数据类型，这里只实现最基础的数据类型定义，后续如果有需要同学们可以自行扩展，用一个枚举类来进行定义，至于为什么要枚举类，后面在实现序列化和反序列化时就能知道了，这里先不解释，定义追加在核心模块目录core下的<strong>init</strong>-py中，代码如下<figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">from</span> enum <span class="keyword">import</span> Enum</span><br><span class="line"><span class="comment">#字段类型枚举</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">FieldType</span>(<span class="params">Enum</span>) :</span></span><br><span class="line">    <span class="comment">#整型</span></span><br><span class="line">    INT = <span class="built_in">int</span> = <span class="string">&quot;int&quot;</span></span><br><span class="line">    <span class="comment">#字符型</span></span><br><span class="line">    VARCHAR = varchar = <span class="string">&quot;str&quot;</span></span><br><span class="line">    <span class="comment">#浮点型</span></span><br><span class="line">    FLOAT = <span class="built_in">float</span> = <span class="string">&quot;float&quot;</span></span><br><span class="line"><span class="comment">#数据类型映射</span></span><br><span class="line">TYPE_MAP = &#123;</span><br><span class="line">    <span class="string">&quot;int&quot;</span> : <span class="built_in">int</span>,</span><br><span class="line">    <span class="string">&quot;float&quot;</span> : <span class="built_in">float</span>,</span><br><span class="line">    <span class="string">&quot;str&quot;</span> : <span class="built_in">str</span>,</span><br><span class="line">    <span class="string">&quot;INT&quot;</span>: <span class="built_in">int</span>,</span><br><span class="line">    <span class="string">&quot;FLOAT&quot;</span> : <span class="built_in">float</span>,</span><br><span class="line">    <span class="string">&quot;VARCHAR&quot;</span> : <span class="built_in">str</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="五、定义数据约束"><a href="#五、定义数据约束" class="headerlink" title="五、定义数据约束"></a>五、定义数据约束</h2></li>
<li>数据约束与数据类型类似，这里依旧是用一个枚举类来实现，定义在核心模块目录core下的.__init_.py 中，代码如下<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#字段主键枚举</span><br><span class="line">class FieldKey (Enum) :</span><br><span class="line">    PRIMARY = &quot;PRIMARY KEY&quot;    #主键约束</span><br><span class="line">    INCREMENT = &quot;AUTO_INCREMENT&quot;    #自增约束</span><br><span class="line">    UNIQUE = &quot;UNIQUE&quot;    #唯一约束</span><br><span class="line">    NOT_NULL = &quot;NOT MULL&quot;    #非空约束</span><br><span class="line">    NULL = &quot;MULL&quot;    #可空约束,作为默认的约束使用</span><br></pre></td></tr></table></figure>
<h2 id="六、实现数据字段模块"><a href="#六、实现数据字段模块" class="headerlink" title="六、实现数据字段模块"></a>六、实现数据字段模块</h2></li>
<li>首先根据上面整理出的那些必备功能属性，定义出 Field类的模型，记得继承上面定义的序列化接口，定义在核心模块目录core下的field.py 中，代码如下:<ul>
<li>数据类型</li>
<li>数据约束</li>
<li>默认值</li>
<li>数据</li>
<li>数据长度</li>
</ul>
</li>
<li>上面的判断和异常抛出都是为了让数据类型和数据约束符合要求而定义的，接下来就来实现增、删、改、查这些基础操作，定义在Field类内部，代码如下</li>
<li>这里核心代码其实就四个，分别是get_data, add , delete,modify，从名字就能看出方法的作用，就不再赘述了，然后另外三个方法则只是类型检查而已。</li>
<li>除了基础操作的四个方法，还有一些需要暴露出来的属性，如rows,type和 keys 这些，依旧定义在Field类中</li>
<li>最后就是序列化和反序列化了，这里我的实现思路是先把对象属性转为一个Json字符串，然后反序列化从这串3son字符串中解析出数据，重新实例化为对象</li>
<li>反序列化方法：它的作用其实就是调用类的静态方法解析Json字符串，从中获取数据，然后再还原成一个对应的对象，反序列化方法首先是对‘Json字符串解析为一个dict，然后从中获取对应的键值进行对象初始化，再调用对象的add方法把数据绑定回去，最后返回这个对象、</li>
</ul>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#判断数据类型是否符合</span><br><span class="line">def __check_type(self, value):</span><br><span class="line">    #如果该值的类型不符合定义好的类型,抛出类型错误异常</span><br><span class="line">    if value is not None and not isinstance(value，TYPE_AAP[self.__type.value]):</span><br><span class="line">        raise TypeError(&#x27;data type error，value must be %s&#x27; % self._type)</span><br><span class="line">#判断指定位置数据是否存在</span><br><span class="line">def _check_index(self,index):</span><br><span class="line">    #如果指定位置不存在,抛出不存在该元素异常</span><br><span class="line">    if not isinstance(index，int) or not -index &lt; self._rows &gt; index:</span><br><span class="line">        raise Exception( &#x27;Not this element&quot;)</span><br><span class="line">    return True</span><br><span class="line">#键值约束</span><br><span class="line">def _check_keys(self, value):</span><br><span class="line">    #如果字段包含自增键,则选择合适的值自动自增</span><br><span class="line">    if FieldKey. INCREMENT in self.__keys:</span><br><span class="line">        #如果值为空,则用字段数据长度作为基值自增</span><br><span class="line">        if value is None:</span><br><span class="line">            value = self.__rows +1</span><br><span class="line">        #如果值已存在，则抛出一个值已经存在的异常</span><br><span class="line">        if value in self.__values:</span><br><span class="line">            raise Exception(&#x27;value %s exists&#x27;% value)</span><br><span class="line">    #如果字段包含主键约束或者唯一约束,判断值是否存在</span><br><span class="line">    if FieldKey.PRIMARY in self.__keys or FieldKey.UNIQUE in self._keys:</span><br><span class="line">        #如果值已存在，抛出存在异常</span><br><span class="line">        if value in self.__values:</span><br><span class="line">            raise Exception(&#x27;value %s exists&#x27;% value)</span><br><span class="line">    #如果该字段包含主键或者非空键，并且添加的值为空值，则抛出值不能为空异常</span><br><span class="line">    if (FieldKey.PRIMARY in self.__keys or FieldKey.NOT_NULL in self._keys) and value is None:</span><br><span class="line">        raise Exception(&quot;Field Not Null&quot;)</span><br><span class="line">    return value</span><br><span class="line">        #删除指定位置数据</span><br><span class="line">def delete(self， index):</span><br><span class="line">    #如果删除的位置不存在,抛出不存在该元素异常</span><br><span class="line">    self.__check_index(index)</span><br><span class="line">    #删除数据</span><br><span class="line">    self.__values.pop(index)</span><br><span class="line">    #教据长度减一</span><br><span class="line">    self.__rows -= 1</span><br><span class="line">    #修改指定位置数据</span><br><span class="line">def modify(self，index,value):</span><br><span class="line">    #如果修改的位置小于o或者大于数据总长度,抛出不存在该元素异常</span><br><span class="line">    self.__check_index( index)</span><br><span class="line">    #判断数据是否符合约束要求</span><br><span class="line">    value = self.__check_keys(value)</span><br><span class="line">    #如果修改的值类型不符合定义好的类型,抛出类型错误异常</span><br><span class="line">    self.__check_type(value)</span><br><span class="line">    #修改数据</span><br><span class="line">    self.__values[index] = value</span><br><span class="line">#获取字段数据约束</span><br><span class="line">def get_keys(self):</span><br><span class="line">    return self.__keys</span><br><span class="line">#获取字段类型</span><br><span class="line">def get_type(self):</span><br><span class="line">    return self.__type</span><br><span class="line">#获取数据长度</span><br><span class="line">def length(self):</span><br><span class="line">    return self.__rows</span><br><span class="line">#序列化对象</span><br><span class="line">def serialized(self):</span><br><span class="line">    return SerializedInterface.json.dumps(&#123;</span><br><span class="line">        &#x27;key&#x27; : [key.value for key in self._keys],</span><br><span class="line">        #数据约束</span><br><span class="line">        &#x27;type&#x27; : self.__type.value,</span><br><span class="line">        #数据类型</span><br><span class="line">        &#x27;values&#x27; : self.__values,</span><br><span class="line">        #数据</span><br><span class="line">        &#x27;default&#x27; : self.__default</span><br><span class="line">        #默认值</span><br><span class="line">    &#125;)</span><br><span class="line">#反序列化为对象</span><br><span class="line">@staticmethod</span><br><span class="line">def deserialized(data):</span><br><span class="line">    #将数据转化为Json 对象</span><br><span class="line">    json_data = SerializedInterface.json.loads(data)</span><br><span class="line">    #转换Json对象中key的值为枚举类FieldKey中的属性</span><br><span class="line">    keys = [FieldKey(key) for key in json_data[&#x27;key&#x27;]</span><br><span class="line">    #传入解析出来的数据类型和字段键并实例化一个 Field 对象</span><br><span class="line">    obj = Field(FieldType(json_data[&#x27;type&#x27;])，keys，default=json_data[ &#x27;default&#x27;])</span><br><span class="line">    #为Field 对象绑定数据</span><br><span class="line">    for value in json_data[&#x27;values&#x27;]:</span><br><span class="line">        obj.add(value)</span><br><span class="line">    #返回该 Field 对象</span><br><span class="line">    return obj</span><br><span class="line">    </span><br></pre></td></tr></table></figure>
<h1 id="数据表模块的实现"><a href="#数据表模块的实现" class="headerlink" title="数据表模块的实现"></a>数据表模块的实现</h1><h2 id="一、实验说明-1"><a href="#一、实验说明-1" class="headerlink" title="一、实验说明"></a>一、实验说明</h2><h3 id="1-1内容-1"><a href="#1-1内容-1" class="headerlink" title="1.1内容"></a>1.1内容</h3><ul>
<li>本节接着上一节实现的数据字段模块，实现在它之上的另一个同为核心模块之一的数据表模块。<h3 id="1-2实验环境"><a href="#1-2实验环境" class="headerlink" title="1.2实验环境"></a>1.2实验环境</h3></li>
<li>Python3<h2 id="二、模块功能分析-1"><a href="#二、模块功能分析-1" class="headerlink" title="二、模块功能分析"></a>二、模块功能分析</h2></li>
<li>这个模块在数据字段摸块之上，也就是数据结构模型中的表，它会包含字段对象Field 构成一张数据表，而且从字段模块可以知道它自身是没有名字的，加上数据结构模型中我们是设计为键值对来存放，所以它需要有一个属性来存放这些健值对，键就是字段名，值就是Field对象，然后数据表的执行动作依旧是增、删、改、查，只不过它会比较复杂，因为操作多了条件判断，这一节条件判断会先搁置，等到后续章节实现条件判断模块那一节中才会回过头来实现。再者就是序列化和反序列化了，总结下来它需要的数据和功能如下<ul>
<li>一个存放Field对象的键值对字典</li>
<li>添加字段操作</li>
<li>支持增、删、改、查操作</li>
<li>序列化和反序列化<h2 id="三、实现数据表模块"><a href="#三、实现数据表模块" class="headerlink" title="三、实现数据表模块"></a>三、实现数据表模块</h2><h3 id="3-1对象的初始化"><a href="#3-1对象的初始化" class="headerlink" title="3.1对象的初始化"></a>3.1对象的初始化</h3></li>
</ul>
</li>
<li>依旧是先实现对象的初始化方法，先看代码再来具体分析，代码如下，定义在core目录下的 table.py文件中<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">from syldb.core import SerializedInterface</span><br><span class="line">from syldb.core.field import Field</span><br><span class="line">#数据表对象</span><br><span class="line">class Table(serializedInterface) :</span><br><span class="line">    def _init__(self,**options):</span><br><span class="line">        self.__field_names = []</span><br><span class="line">        #数据表所有字段名</span><br><span class="line">        self.__field_objs =&#123;&#125;</span><br><span class="line">        #数据表字段名与字段对象映射</span><br><span class="line">        self._rows = 0</span><br><span class="line">        #数据条目数</span><br><span class="line">        </span><br><span class="line">        #获取所有字段名和字段对象为数据表初始化字段</span><br><span class="line">        for field_name, field_obj in options.items():</span><br><span class="line">            #进行字段添加</span><br><span class="line">            self.add_field(field_name，field_obj)</span><br></pre></td></tr></table></figure>
</li>
</ul>

      
    </div>
    <footer class="article-footer">
      <a data-url="https://goofyer.gitee.io/notes-on-computer-expertise/2022/02/23/python/python%E7%BC%96%E5%86%99%E5%B0%8F%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93/" data-id="cl403sxrj0026f8vuazakfd6r" data-title="" class="article-share-link">Share</a>
      
      
      
    </footer>
  </div>
  
</article>



  


  <nav id="page-nav">
    
    <a class="extend prev" rel="prev" href="/notes-on-computer-expertise/">&laquo; Prev</a><a class="page-number" href="/notes-on-computer-expertise/">1</a><span class="page-number current">2</span><a class="page-number" href="/notes-on-computer-expertise/page/3/">3</a><a class="page-number" href="/notes-on-computer-expertise/page/4/">4</a><span class="space">&hellip;</span><a class="page-number" href="/notes-on-computer-expertise/page/14/">14</a><a class="extend next" rel="next" href="/notes-on-computer-expertise/page/3/">Next &raquo;</a>
  </nav>

</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/C-%E5%B7%A5%E5%85%B7/">C#工具</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/C-%E5%B7%A5%E5%85%B7/">C++工具</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/Mysql/">Mysql</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/blender/">blender</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/linux/">linux</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/manim/">manim</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/spring/">spring</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/vba%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C/">vba基础操作</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E5%88%9B%E9%80%A0%E6%A8%A1%E5%BC%8F/">创造模式</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/">操作系统</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/">操作系统基础知识</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%BC%80%E5%8F%91/">操作系统开发</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%95%B0%E5%AD%A6/">数学</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/">数据结构</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/">数据结构基础知识</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%A8%A1%E6%9D%BF/">模板</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/">深度学习</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E8%8B%B1%E8%AF%AD/">英语</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E8%99%9A%E5%B9%BB4/">虚幻4</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/">计算机组成原理</a></li><li class="category-list-item"><a class="category-list-link" href="/notes-on-computer-expertise/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/">计算机网络</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/notes-on-computer-expertise/tags/C/" rel="tag">C++</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/notes-on-computer-expertise/tags/C/" style="font-size: 10px;">C++</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/notes-on-computer-expertise/archives/2022/05/">May 2022</a></li><li class="archive-list-item"><a class="archive-list-link" href="/notes-on-computer-expertise/archives/2022/03/">March 2022</a></li><li class="archive-list-item"><a class="archive-list-link" href="/notes-on-computer-expertise/archives/2022/02/">February 2022</a></li><li class="archive-list-item"><a class="archive-list-link" href="/notes-on-computer-expertise/archives/2022/01/">January 2022</a></li><li class="archive-list-item"><a class="archive-list-link" href="/notes-on-computer-expertise/archives/2021/12/">December 2021</a></li></ul>
    </div>
  </div>


  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recent Posts</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/notes-on-computer-expertise/2022/05/31/vue/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6%E9%AA%8C%E8%AF%81%E7%A0%81%E6%97%A0%E6%B3%95%E6%98%BE%E7%A4%BA/">(no title)</a>
          </li>
        
          <li>
            <a href="/notes-on-computer-expertise/2022/05/26/%E6%95%B0%E6%8D%AE%E5%BA%93/navicat%E5%AE%89%E8%A3%85/">(no title)</a>
          </li>
        
          <li>
            <a href="/notes-on-computer-expertise/2022/05/25/%E8%99%9A%E5%B9%BB4%E5%BC%95%E6%93%8E%E5%BC%80%E5%8F%91/%E8%99%9A%E5%B9%BB%E5%9B%9B%20mod%E5%88%B6%E4%BD%9C/">(no title)</a>
          </li>
        
          <li>
            <a href="/notes-on-computer-expertise/2022/05/23/python/python%E6%89%B9%E9%87%8F%E7%94%9F%E6%88%90%E6%95%B0%E6%8D%AE/">(no title)</a>
          </li>
        
          <li>
            <a href="/notes-on-computer-expertise/2022/05/23/vba%E5%9F%BA%E7%A1%80%E6%93%8D%E4%BD%9C%E7%AC%94%E8%AE%B0/EXCEL%E5%9F%BA%E7%A1%80%E6%95%99%E7%A8%8B/">(no title)</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      
      &copy; 2022 John Doe<br>
      Powered by <a href="https://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>

    </div>
    <nav id="mobile-nav">
  
    <a href="/notes-on-computer-expertise/" class="mobile-nav-link">Home</a>
  
    <a href="/notes-on-computer-expertise/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="/notes-on-computer-expertise/js/jquery-3.4.1.min.js"></script>



  
<script src="/notes-on-computer-expertise/fancybox/jquery.fancybox.min.js"></script>




<script src="/notes-on-computer-expertise/js/script.js"></script>





  </div>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
        tex2jax: {
            inlineMath: [ ["$","$"], ["\\(","\\)"] ],
            skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'],
            processEscapes: true
        }
    });
    MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax();
        for (var i = 0; i < all.length; ++i)
            all[i].SourceElement().parentNode.className += ' has-jax';
    });
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script>
</body>
</html>